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

  1. Ensure the full marshaledSize bytes are stored and retrieved unchanged (verify byte-for-byte length).
  2. If the data passes through a length-prefixed protocol, check the length prefix matches the expected marshaledSize before forwarding.
  3. Re-hash from the original input if the state is unrecoverable.
  4. 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

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


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/c0b776629253a26f. Report an issue: GitHub.