golang/go · error

crypto/md5: invalid hash state identifier

Error message

crypto/md5: invalid hash state identifier

What it means

Returned by md5 digest.UnmarshalBinary when the input is shorter than the magic prefix or the prefix does not equal md5's magic constant. The magic identifies the bytes as MD5 state; a mismatch means the data is not a valid MD5 serialized state (or belongs to a different hash).

Source

Thrown at src/crypto/md5/md5.go:83

func (d *digest) MarshalBinary() ([]byte, error) {
	return d.AppendBinary(make([]byte, 0, marshaledSize))
}

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])
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Verify the bytes were produced by md5's MarshalBinary on the same Go version.
  2. If migrating from another hash, re-hash from the original input.
  3. Check len(b) >= len(magic) before calling and treat shorter buffers as corrupt.
  4. Prefer SHA-256 over MD5 for any new code (MD5 is cryptographically broken).

Example fix

// before
d.UnmarshalBinary(sha1StateBytes) // wrong magic -> error
// after
d.UnmarshalBinary(md5StateBytes) // produced by md5 MarshalBinary
Defensive patterns

Strategy: validation

Validate before calling

if len(b) < len(magic) || string(b[:len(magic)]) != magic {
    return errors.New("not MD5 marshaled state")
}

Prevention

When it happens

Trigger: Calling UnmarshalBinary on an MD5 digest with bytes from another hash (SHA-1, SHA-256), corrupted bytes, an empty buffer, or a buffer shorter than the magic prefix.

Common situations: Persisting MD5 hash state and reloading it with corrupted or empty data; sending hash state over a protocol where another hash writes the same field; downgrading code that previously used a stronger hash and forgetting to migrate the stored state.

Related errors


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