{"record":{"id":"87e130d97c818bf6","repo":"dgraph-io/badger","slug":"ptrs-and-entries-don-t-match-v","errorCode":null,"errorMessage":"Ptrs and Entries don't match: %+v","messagePattern":"Ptrs and Entries don't match: %\\+v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"db.go","lineNumber":829,"sourceCode":"\t\tif maxVs.Version < vs.Version {\n\t\t\tmaxVs = vs\n\t\t}\n\t}\n\treturn db.lc.get(key, maxVs, 0)\n}\n\nvar requestPool = sync.Pool{\n\tNew: func() interface{} {\n\t\treturn new(request)\n\t},\n}\n\nfunc (db *DB) writeToLSM(b *request) error {\n\t// We should check the length of b.Prts and b.Entries only when badger is not\n\t// running in InMemory mode. In InMemory mode, we don't write anything to the\n\t// value log and that's why the length of b.Ptrs will always be zero.\n\tif !db.opt.InMemory && len(b.Ptrs) != len(b.Entries) {\n\t\treturn fmt.Errorf(\"Ptrs and Entries don't match: %+v\", b)\n\t}\n\n\tfor i, entry := range b.Entries {\n\t\tvar err error\n\t\tif entry.skipVlogAndSetThreshold(db.valueThreshold()) {\n\t\t\t// Will include deletion / tombstone case.\n\t\t\terr = db.mt.Put(entry.Key,\n\t\t\t\ty.ValueStruct{\n\t\t\t\t\tValue: entry.Value,\n\t\t\t\t\t// Ensure value pointer flag is removed. Otherwise, the value will fail\n\t\t\t\t\t// to be retrieved during iterator prefetch. `bitValuePointer` is only\n\t\t\t\t\t// known to be set in write to LSM when the entry is loaded from a backup\n\t\t\t\t\t// with lower ValueThreshold and its value was stored in the value log.\n\t\t\t\t\tMeta:      entry.meta &^ bitValuePointer,\n\t\t\t\t\tUserMeta:  entry.UserMeta,\n\t\t\t\t\tExpiresAt: entry.ExpiresAt,\n\t\t\t\t})\n\t\t} else {","sourceCodeStart":811,"sourceCodeEnd":847,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/db.go#L811-L847","documentation":"writeToLSM verifies that each write request's entry list and its corresponding vlog pointer list are the same length, since every entry must map to exactly one pointer. A mismatch is an internal invariant violation, skipped only in InMemory mode where no pointers are produced.","triggerScenarios":"Writing via db.Write, db.Commit, or writeRequests where the request's Ptrs and Entries slices diverged — effectively only reachable from internal bugs or custom code constructing request structs directly (e.g. in forks/tests).","commonSituations":"Patching badger internals or building manual write requests; concurrency bugs in code that mutates a request between vlog write and LSM write; InMemory mismatch confusion.","solutions":["Report/fix the bug in the code constructing the request so len(Ptrs) == len(Entries)","Never mutate b.Ptrs or b.Entries after submitting to writeRequests","Upgrade badger — if hit on stock write APIs, it is a library bug"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if len(req.Ptrs) != len(req.Entries) {\n    return fmt.Errorf(\"bad request: %d ptrs vs %d entries\", len(req.Ptrs), len(req.Entries))\n}","typeGuard":"func requestSane(r *request) bool { return len(r.Ptrs) == len(r.Entries) || inMemoryMode }","tryCatchPattern":"if err := db.writeToLSM(req); err != nil {\n    if strings.Contains(err.Error(), \"Ptrs and Entries don't match\") {\n        log.Fatalf(\"internal bug: dump req entries=%d ptrs=%d\", len(req.Entries), len(req.Ptrs))\n    }\n}","preventionTips":["Never hand-construct request structs; use txns (Set/Delete/Commit)","Don't mutate req.Ptrs/Entries after submission","On badger forks, add this length check early with tests"],"tags":["badger","internal","invariant-violation"],"backgroundTag":"internal-invariant-violation","analyzedSha":"2a001d466f6b71a917319a1db41f99860e16e269","analyzedAt":"2026-09-05T13:00:02.264Z","contentChangedAt":"2026-09-05T13:00:02.264Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}