{"record":{"id":"656013d0cd68b9e9","repo":"golang/go","slug":"crypto-md5-invalid-hash-state-size","errorCode":null,"errorMessage":"crypto/md5: invalid hash state size","messagePattern":"crypto/md5: invalid hash state size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/md5/md5.go","lineNumber":86,"sourceCode":"\nfunc (d *digest) AppendBinary(b []byte) ([]byte, error) {\n\tb = append(b, magic...)\n\tb = byteorder.BEAppendUint32(b, d.s[0])\n\tb = byteorder.BEAppendUint32(b, d.s[1])\n\tb = byteorder.BEAppendUint32(b, d.s[2])\n\tb = byteorder.BEAppendUint32(b, d.s[3])\n\tb = append(b, d.x[:d.nx]...)\n\tb = append(b, make([]byte, len(d.x)-d.nx)...)\n\tb = byteorder.BEAppendUint64(b, d.len)\n\treturn b, nil\n}\n\nfunc (d *digest) UnmarshalBinary(b []byte) error {\n\tif len(b) < len(magic) || string(b[:len(magic)]) != magic {\n\t\treturn errors.New(\"crypto/md5: invalid hash state identifier\")\n\t}\n\tif len(b) != marshaledSize {\n\t\treturn errors.New(\"crypto/md5: invalid hash state size\")\n\t}\n\tb = b[len(magic):]\n\tb, d.s[0] = consumeUint32(b)\n\tb, d.s[1] = consumeUint32(b)\n\tb, d.s[2] = consumeUint32(b)\n\tb, d.s[3] = consumeUint32(b)\n\tb = b[copy(d.x[:], b):]\n\tb, d.len = consumeUint64(b)\n\td.nx = int(d.len % BlockSize)\n\treturn nil\n}\n\nfunc consumeUint64(b []byte) ([]byte, uint64) {\n\treturn b[8:], byteorder.BEUint64(b[0:8])\n}\n\nfunc consumeUint32(b []byte) ([]byte, uint32) {\n\treturn b[4:], byteorder.BEUint32(b[0:4])","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/md5/md5.go#L68-L104","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nd.UnmarshalBinary(b[:len(b)-2]) // truncated -> error\n// after\nd.UnmarshalBinary(b) // full marshaledSize","handlingStrategy":"validation","validationCode":"if len(b) != marshaledSize {\n    return fmt.Errorf(\"md5 state size mismatch: got %d want %d\", len(b), marshaledSize)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["crypto","hash","md5","serialization","go-stdlib"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}