Why is my SHA-256 hash different
Tools Nimbus is a free, no-signup developer toolkit that runs entirely in your browser, so your data is never uploaded to a server. A SHA-256 hash is deterministic, so two different results always mean two different inputs: a trailing newline, CRLF line endings, a text-encoding mismatch, or uppercase versus lowercase hex output. Paste each version into the Tools Nimbus Hash Generator, free with no signup, to find the byte that differs.
Last updated July 2026
A hash is deterministic. Different output means different input.
SHA-256 is a pure function of its input bytes. The same bytes always produce the same 256-bit digest, on any machine, in any language, forever. So when you get two different hashes for what looks like the same text, the text was not actually the same at the byte level. There is no randomness, no timestamp, and no per-run seed in a plain hash. That makes debugging refreshingly mechanical: instead of asking why the hash changed, find the byte that changed.
This is also why the two hashes look completely unrelated rather than "close." SHA-256 has an avalanche effect, so flipping a single input bit changes roughly half of the output bits. A one-character difference does not produce a one-character difference in the digest; it produces a totally different-looking string. Do not read anything into how similar or dissimilar the two hashes are.
Symptom, cause, and fix at a glance
| Symptom | Most likely cause | Fix |
|---|---|---|
| Hash of a file differs from hash of pasted text | Trailing newline in the file | Strip or match the trailing newline on both sides |
| Hash differs between Windows and macOS/Linux | CRLF (\r\n) versus LF (\n) line endings | Normalize line endings before hashing |
| Hash differs between two apps or languages | Different text encoding (UTF-8 vs UTF-16, or a BOM) | Encode as UTF-8 with no BOM on both sides |
| Hashes look equal but a string compare says no | Uppercase vs lowercase hex output | Lowercase both, or compare raw bytes |
| Accented text hashes differently | Unicode normalization (NFC vs NFD) | Normalize to NFC before hashing |
| Server hash never matches yours | Server uses a salt, HMAC key, or hashes JSON, not raw text | Match the exact input and algorithm the server uses |
Cause 1: a trailing newline (the usual culprit)
This is the most common reason a hash of a file does not match a hash of the "same" text. A newline is a real byte, so echo "hello" | sha256sum hashes six bytes (hello\n) while pasting hello into a tool hashes five. The digests are entirely different. Text editors frequently add a final newline on save, and many shell tools do too. Use printf instead of echo (or echo -n) to drop the newline, and decide on one convention, with or without a trailing newline, for both sides.
Cause 2: CRLF versus LF line endings
Windows editors and Git configured with autocrlf store line breaks as \r\n (carriage return plus line feed), while macOS and Linux use a bare \n. That extra \r byte on every line changes the hash completely. If the same content hashes differently on two operating systems, or before and after a Git checkout, line endings are almost always the reason. Normalize to LF (or to CRLF) everywhere before hashing, and be aware that .gitattributes rules can silently rewrite line endings underneath you.
Cause 3: text encoding and byte-order marks
SHA-256 hashes bytes, not characters, so the encoding you use to turn text into bytes matters. The letter eis one byte in UTF-8 but two bytes in UTF-16, and a Windows "Save as UTF-8" may prepend a three-byte byte-order mark (EF BB BF) that you never see but that changes the hash. If two programs or two languages disagree on a hash, confirm both encode the string as UTF-8 with no BOM. This is the same class of bug that produces mojibake; see why Base64 decodes to garbled text for the encoding side of it.
Cause 4: Unicode normalization
Some accented and composed characters can be represented two ways that look identical on screen. The character é can be a single code point (NFC) or a plain e followed by a combining accent (NFD). Those are different byte sequences, so they hash differently even though the text is visually the same. macOS filenames, for instance, historically use NFD. If accented or non-Latin text hashes differently across systems, normalize both inputs to NFC (for example str.normalize("NFC") in JavaScript) before hashing.
Cause 5: uppercase versus lowercase hex
Sometimes the digests are actually identical and only their text representation differs. A SHA-256 result is 32 raw bytes; tools print those bytes as 64 hexadecimal characters, and some print a3f1... in lowercase while others print A3F1... in uppercase. A case-sensitive === or string equality check then reports a mismatch on hashes that are genuinely equal. Lowercase both strings before comparing them, or compare the raw byte arrays rather than the formatted hex.
Cause 6: the server is not hashing what you think
When your local hash never matches a server or database value, the two sides are probably not hashing the same thing. A password store applies a per-user salt (and usually a slow algorithm like bcrypt, not raw SHA-256), so the same password yields a different digest for every user by design. An API signature may be an HMAC, which mixes in a secret key. A record hash may cover a serialized JSON object whose key order or whitespace differs from your input. Match the exact bytes, salt, key, and algorithm the other side uses, and remember that a hash is one-way; see encoding vs encryption vs hashing for where hashing fits.
Find the difference in one step
You do not have to guess which cause you are hitting. Open the Hash Generator, paste each version of your text, and read the SHA-256 output for each. If the two hashes match, your inputs were identical and the mismatch was downstream (a case-sensitive compare, or a different algorithm). If they differ, the inputs differ, and the fastest way to see how is to drop both strings into the Diff Checker, which highlights a stray trailing newline, an extra space, or a swapped character that is invisible in a normal text field. Because both tools run entirely in your browser using the native Web Crypto API, the text you paste never leaves your device.
How to prevent it
- Decide on a trailing-newline convention and apply it on both sides;
printfandecho -nomit the newline thatechoadds. - Normalize line endings (pick LF or CRLF) before hashing, and watch for Git
autocrlfrewriting them. - Standardize on UTF-8 with no BOM end to end, and normalize Unicode to NFC when the text may contain accents.
- Compare hashes case-insensitively, or compare raw bytes, so uppercase and lowercase hex never trip you up.
- Confirm the algorithm and inputs match: a salted password hash or an HMAC will never equal a plain SHA-256 of the same text. For picking a hasher, see the best free SHA-256 hash generator, and browse the Tools Nimbus guides for more developer fixes.