{"record":{"id":"9822027d2bfe3507","repo":"weaviate/weaviate","slug":"count-d-too-large-for-remaining-d-bytes","errorCode":null,"errorMessage":"count %d too large for remaining %d bytes","messagePattern":"count (.+?) too large for remaining (.+?) bytes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"adapters/repos/db/lsmkv/gobenc/gobenc.go","lineNumber":239,"sourceCode":"\t}\n\tpos++\n\n\tcount, n, err := readGobUint(data, pos)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"read map count: %w\", err)\n\t}\n\tpos += n\n\n\t// the count varint is bounded only against len(data), so it can run past\n\t// msgEnd; without this, uint64(msgEnd-pos) underflows and the guard below\n\t// admits a huge count that make([]uint64, count) panics on.\n\tif pos > msgEnd {\n\t\treturn nil, nil, fmt.Errorf(\"map count truncated: read to offset %d past message end %d\", pos, msgEnd)\n\t}\n\n\t// Each entry is at least 2 bytes (1 byte key + 1 byte value).\n\tif count > uint64(msgEnd-pos)/2 {\n\t\treturn nil, nil, fmt.Errorf(\"count %d too large for remaining %d bytes\", count, msgEnd-pos)\n\t}\n\n\tids := make([]uint64, count)\n\tlens := make([]uint32, count)\n\n\tfor i := range count {\n\t\tkey, n, err := readGobUint(data, pos)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"read key %d: %w\", i, err)\n\t\t}\n\t\tpos += n\n\n\t\tval, n, err := readGobUint(data, pos)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"read value %d: %w\", i, err)\n\t\t}\n\t\tpos += n\n","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/weaviate/weaviate/blob/75aa4b6d11f8818305aafd4440b4e32794f7ca04/adapters/repos/db/lsmkv/gobenc/gobenc.go#L221-L257","documentation":"The declared map count exceeds what the remaining bytes could possibly hold: each entry requires at least 2 bytes (1 for key, 1 for value), so count > remaining/2 is impossible for well-formed data. This guard exists to prevent a huge count from reaching make([]uint64, count) and panicking on allocation.","triggerScenarios":"Calling DecodePairs/Decode on data where the count varint decodes to a value larger than (msgEnd-pos)/2 — typical of corrupted or adversarial/fuzz input.","commonSituations":"Flipped bits in the count field, data written by a different encoder version, or deliberate malformed payloads surfaced by fuzz testing (see TestDecodePairsMalformedCountNoPanic).","solutions":["Reject the record as malformed; do not attempt re-decoding the same bytes.","Restore the record from a replica/backup or replay it from the WAL.","Compare the count field against the message length manually to locate the corruption.","Keep this guard in place — removing it reintroduces an allocation-panic DoS on untrusted input."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"remaining := uint64(msgEnd - pos)\nif count > remaining/2 { /* malformed: reject before allocating */ }","typeGuard":null,"tryCatchPattern":"if _, _, err := gobenc.DecodePairs(data); err != nil {\n    log.Warnf(\"rejecting malformed map record: %v\", err)\n    return errSkipRecord\n}","preventionTips":["Never remove the count-vs-remaining sanity check — it prevents an allocation panic.","Fuzz the decoder with large count values (see TestDecodePairsMalformedCountNoPanic).","Treat any count that fails the 2-bytes-per-entry bound as disk corruption."],"tags":["gob","lsmkv","decoding","corruption","dos-hardening"],"backgroundTag":"gob-decode-count-mismatch","analyzedSha":"75aa4b6d11f8818305aafd4440b4e32794f7ca04","analyzedAt":"2026-09-04T14:58:20.392Z","contentChangedAt":"2026-09-04T14:58:20.392Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}