{"record":{"id":"00468b7eebe611cb","repo":"dgraph-io/badger","slug":"invalid-value-pointer-offset-d-greater-than-curr","errorCode":null,"errorMessage":"Invalid value pointer offset: %d greater than current offset: %d","messagePattern":"Invalid value pointer offset: (.+?) greater than current offset: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"value.go","lineNumber":953,"sourceCode":"// Gets the logFile and acquires and RLock() for the mmap. You must call RUnlock on the file\n// (if non-nil)\nfunc (vlog *valueLog) getFileRLocked(vp valuePointer) (*logFile, error) {\n\tvlog.filesLock.RLock()\n\tdefer vlog.filesLock.RUnlock()\n\tret, ok := vlog.filesMap[vp.Fid]\n\tif !ok {\n\t\t// log file has gone away, we can't do anything. Return.\n\t\treturn nil, fmt.Errorf(\"file with ID: %d not found\", vp.Fid)\n\t}\n\n\t// Check for valid offset if we are reading from writable log.\n\tmaxFid := vlog.maxFid\n\t// In read-only mode we don't need to check for writable offset as we are not writing anything.\n\t// Moreover, this offset is not set in readonly mode.\n\tif !vlog.opt.ReadOnly && vp.Fid == maxFid {\n\t\tcurrentOffset := vlog.woffset()\n\t\tif vp.Offset >= currentOffset {\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"Invalid value pointer offset: %d greater than current offset: %d\",\n\t\t\t\tvp.Offset, currentOffset)\n\t\t}\n\t}\n\n\tret.lock.RLock()\n\treturn ret, nil\n}\n\n// Read reads the value log at a given location.\n// TODO: Make this read private.\nfunc (vlog *valueLog) Read(vp valuePointer, _ *y.Slice) ([]byte, func(), error) {\n\tbuf, lf, err := vlog.readValueBytes(vp)\n\t// log file is locked so, decide whether to lock immediately or let the caller to\n\t// unlock it, after caller uses it.\n\tcb := vlog.getUnlockCallback(lf)\n\tif err != nil {\n\t\treturn nil, cb, err","sourceCodeStart":935,"sourceCodeEnd":971,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/value.go#L935-L971","documentation":"After locating the log file for a value pointer, getFileRLocked validates the offset: when reading from the currently writable log (vp.Fid == maxFid, non-readonly), the pointer's offset must be strictly less than the log's current write offset (vlog.woffset()). A value pointer at or past the write head points at data that was never durably written, indicating truncation or corruption.","triggerScenarios":"Reading a value whose valuePointer offset >= the writable file's current offset — typically after a crash where the unsynced vlog tail was lost but an SST still holds a newer valuePointer, a corrupted valuePointer, or a manually truncated vlog file.","commonSituations":"Unsynced writes + hard crash/power loss; disk corruption or partial vlog truncation; restoring an older vlog file alongside newer SSTs (file-set version mismatch).","solutions":["Restore LSM and vlog files as a consistent set from the same backup timestamp — never mix files from different points in time.","Reduce crash-tail risk by enabling/tuning opt.SyncWrites; badger truncates the vlog tail on recovery, so SSTs must match the recovered state.","If corruption is suspected, use badger recovery/verification tooling or rebuild via Stream/Backup into a fresh instance.","Check hardware/disk issues (dmesg, fsck) if the write head regressed unexpectedly.","Mitigate by iterating and rewriting affected key ranges so valuePointers are regenerated against current vlog state."],"exampleFix":"// before: mixing a new SST backup with an older vlog file\n$ cp new.sst /data/badger/ && cp old-000005.vlog /data/badger/\n// read: Invalid value pointer offset: 9500 greater than current offset: 8192\n// after: restore a consistent snapshot\n$ rsync --archive snapshot@ts/ /data/badger/  # SSTs and vlogs from same checkpoint\n// and reduce crash tail risk\nopt.SyncWrites = true","handlingStrategy":"retry","validationCode":"// Go: validate restore consistency — SST and vlog file timestamps should match\nfunc restoreConsistent(snapshotDir, dataDir string) error {\n    sstT := modTimeFirst(snapshotDir, \"*.sst\")\n    vlogT := modTimeFirst(snapshotDir, \"*.vlog\")\n    if !sstT.Equal(vlogT) && sstT.Sub(vlogT).Abs() > time.Minute {\n        return errors.New(\"mixed vlog/SST generations — restore full snapshot\")\n    }\n    return nil\n}","typeGuard":"func isInvalidVpOffset(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"Invalid value pointer offset\")\n}","tryCatchPattern":"item, err := txn.Get(key)\nif err != nil && isInvalidVpOffset(err) {\n    // retry after rewriting the key to regenerate its value pointer\n    if rwErr := regenerateAndPut(key); rwErr != nil {\n        return rwErr\n    }\n    return txn.Get(key)\n}","preventionTips":["Always restore SSTs and vlogs from the same snapshot timestamp.","Enable opt.SyncWrites to shrink the unsynced crash tail.","Never truncate or edit vlog files by hand.","Check disk health after unclean shutdowns before reopening."],"tags":["badger","value-log","corruption","crash-recovery"],"backgroundTag":"invalid-value-pointer-offset","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"}