golang/go · error
crypto/sha256: invalid hash state size
Error message
crypto/sha256: invalid hash state size
What it means
Returned by sha256 Digest.UnmarshalBinary when the magic prefix is correct but the total byte length is not marshaledSize. The serialized layout is fixed-length (magic + 8 x uint32 state + 64-byte block buffer + uint64 length counter); any truncation or extra trailing bytes fail this check.
Source
Thrown at src/crypto/internal/fips140/sha256/sha256.go:94
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
}
func consumeUint64(b []byte) ([]byte, uint64) {
return b[8:], byteorder.BEUint64(b)View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure the full marshaledSize bytes are stored and retrieved unchanged (verify byte-for-byte length).
- If the data passes through a length-prefixed protocol, check the length prefix matches the expected marshaledSize before forwarding.
- Re-hash from the original input if the state is unrecoverable.
- Pin the producer and consumer to the same Go major version when persisting hash state long-term.
Example fix
// before buf := stored[:len(stored)-4] // accidentally truncated d.UnmarshalBinary(buf) // valid magic, wrong size -> error // after d.UnmarshalBinary(stored) // full marshaledSize bytes
Defensive patterns
Strategy: validation
Validate before calling
if len(b) != marshaledSize {
return fmt.Errorf("sha256 state size mismatch: got %d want %d", len(b), marshaledSize)
} Prevention
- Verify byte-for-byte length of persisted hash state on read and write.
- Use io.ReadFull and check the error when loading the buffer.
- Pin producer and consumer to the same Go major version for long-lived persisted state.
When it happens
Trigger: Passing bytes whose magic is valid but length differs from the fixed marshaledSize constant: a buffer truncated by a length-prefixed framer, a buffer with extra bytes appended by a buggy serializer, or a buffer from a different Go version whose marshaled layout differs.
Common situations: Database BLOB column sized too small and silently truncating; a copy/paste that lost trailing bytes; version skew between the Go build that marshaled the state and the one unmarshaling it (the marshaled size has historically been stable but is not an API contract).
Related errors
- crypto/sha256: invalid hash state identifier
- 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/c0b776629253a26f.
Report an issue: GitHub.