golang/go · error
crypto/sha256: invalid hash state identifier
Error message
crypto/sha256: invalid hash state identifier
What it means
Returned by sha256 Digest.UnmarshalBinary when the input is shorter than the magic prefix or the prefix does not equal magic224 ('sha\x03') for a SHA-224 digest or magic256 ('sha\x04') for a SHA-256 digest. The magic identifies which variant produced the marshaled state; a mismatch means the bytes are not a valid SHA-256/224 serialized state (or are the wrong variant).
Source
Thrown at src/crypto/internal/fips140/sha256/sha256.go:91
b = append(b, magic256...)
}
b = byteorder.BEAppendUint32(b, d.h[0])
b = byteorder.BEAppendUint32(b, d.h[1])
b = byteorder.BEAppendUint32(b, d.h[2])
b = byteorder.BEAppendUint32(b, d.h[3])
b = byteorder.BEAppendUint32(b, d.h[4])
b = byteorder.BEAppendUint32(b, d.h[5])
b = byteorder.BEAppendUint32(b, d.h[6])
b = byteorder.BEAppendUint32(b, d.h[7])
b = append(b, d.x[:d.nx]...)
b = append(b, make([]byte, len(d.x)-d.nx)...)
b = byteorder.BEAppendUint64(b, d.len)
return b, nil
}
func (d *Digest) UnmarshalBinary(b []byte) error {
if len(b) < len(magic224) || (d.is224 && string(b[:len(magic224)]) != magic224) || (!d.is224 && string(b[:len(magic256)]) != magic256) {
return errors.New("crypto/sha256: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("crypto/sha256: invalid hash state size")
}
b = b[len(magic224):]
b, d.h[0] = consumeUint32(b)
b, d.h[1] = consumeUint32(b)
b, d.h[2] = consumeUint32(b)
b, d.h[3] = consumeUint32(b)
b, d.h[4] = consumeUint32(b)
b, d.h[5] = consumeUint32(b)
b, d.h[6] = consumeUint32(b)
b, d.h[7] = consumeUint32(b)
b = b[copy(d.x[:], b):]
b, d.len = consumeUint64(b)
d.nx = int(d.len % chunk)
return nil
}View on GitHub (pinned to b6b368adc5)
Solutions
- Verify the marshaled bytes came from the exact same digest variant (SHA-256 vs SHA-224) on the producing side.
- If migrating variants, re-hash the original input from scratch rather than trying to cross-unmarshal.
- Store the algorithm name alongside the marshaled state and dispatch UnmarshalBinary to a digest of the matching type.
- Check len(b) >= len(magic) before calling and treat anything shorter as corrupt.
Example fix
// before var d sha256.Digest (224 variant) d.UnmarshalBinary(stateFromSHA256) // wrong magic // after var d sha256.Digest (256 variant matching producer) d.UnmarshalBinary(stateFromSHA256)
Defensive patterns
Strategy: validation
Validate before calling
const magic256 = "sha\x04"
if len(b) < len(magic256) || string(b[:len(magic256)]) != magic256 {
return errors.New("not SHA-256 marshaled state")
} Prevention
- Tag persisted hash state with the algorithm name and verify the tag before UnmarshalBinary.
- Always pair a producer's MarshalBinary with the matching variant's UnmarshalBinary.
- Re-hash from the original input when the variant changes rather than cross-unmarshaling.
When it happens
Trigger: Calling UnmarshalBinary on a SHA-256 digest with bytes from SHA-224 (or vice versa), bytes from a different hash, corrupted bytes, or a truncated buffer that drops the magic prefix entirely.
Common situations: Persisting hash state to a database column and loading it back with the wrong schema version; sending hash state over a protocol where another hash family writes the same field; calling UnmarshalBinary on a SHA-256 digest for state that was marshaled before a code change switched the algorithm to SHA-224.
Related errors
- crypto/sha256: invalid hash state size
- crypto/sha256: invalid hash state identifier
- sha3: invalid hash state
- sha3: invalid hash state identifier
- sha3: invalid hash state function
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/bea8763a02cd87d4.
Report an issue: GitHub.