golang/go · error
crypto/md5: invalid hash state size
Error message
crypto/md5: invalid hash state size
What it means
Returned by md5 digest.UnmarshalBinary when the magic prefix is correct but the total byte length is not marshaledSize. The md5 layout is fixed-length (magic + 4 x uint32 state + 64-byte block buffer + uint64 length counter); any truncation or extra bytes fail this check.
Source
Thrown at src/crypto/md5/md5.go:86
func (d *digest) AppendBinary(b []byte) ([]byte, error) {
b = append(b, magic...)
b = byteorder.BEAppendUint32(b, d.s[0])
b = byteorder.BEAppendUint32(b, d.s[1])
b = byteorder.BEAppendUint32(b, d.s[2])
b = byteorder.BEAppendUint32(b, d.s[3])
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(magic) || string(b[:len(magic)]) != magic {
return errors.New("crypto/md5: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("crypto/md5: invalid hash state size")
}
b = b[len(magic):]
b, d.s[0] = consumeUint32(b)
b, d.s[1] = consumeUint32(b)
b, d.s[2] = consumeUint32(b)
b, d.s[3] = consumeUint32(b)
b = b[copy(d.x[:], b):]
b, d.len = consumeUint64(b)
d.nx = int(d.len % BlockSize)
return nil
}
func consumeUint64(b []byte) ([]byte, uint64) {
return b[8:], byteorder.BEUint64(b[0:8])
}
func consumeUint32(b []byte) ([]byte, uint32) {
return b[4:], byteorder.BEUint32(b[0:4])View on GitHub (pinned to b6b368adc5)
Solutions
- Store and retrieve the full marshaledSize bytes unchanged; verify byte-for-byte length.
- If the buffer transits a length-prefixed protocol, check the length prefix matches marshaledSize.
- Re-hash from the original input if the state is unrecoverable.
- Pin producer and consumer Go major versions when persisting MD5 state long-term.
Example fix
// before d.UnmarshalBinary(b[:len(b)-2]) // truncated -> error // after d.UnmarshalBinary(b) // full marshaledSize
Defensive patterns
Strategy: validation
Validate before calling
if len(b) != marshaledSize {
return fmt.Errorf("md5 state size mismatch: got %d want %d", len(b), marshaledSize)
} Prevention
- Verify byte-for-byte length of persisted state on read and write.
- Use io.ReadFull and check the error when loading.
- Pin producer and consumer Go major versions for long-lived persisted state.
When it happens
Trigger: Passing bytes whose magic is valid but length differs from the fixed marshaledSize: a truncated buffer, an extra byte appended, or bytes from a build whose marshaled layout differs.
Common situations: Database BLOB column truncating; a framing bug that drops or duplicates bytes; version skew between the Go build that marshaled the state and the one unmarshaling it.
Related errors
- crypto/md5: invalid hash state identifier
- crypto/sha256: invalid hash state identifier
- crypto/sha256: invalid hash state size
- sha3: invalid hash state
- sha3: invalid hash state identifier
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/656013d0cd68b9e9.
Report an issue: GitHub.