dgraph-io/badger · error
Invalid value pointer offset: %d greater than current offset
Error message
Invalid value pointer offset: %d greater than current offset: %d
What it means
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.
Source
Thrown at value.go:953
// Gets the logFile and acquires and RLock() for the mmap. You must call RUnlock on the file
// (if non-nil)
func (vlog *valueLog) getFileRLocked(vp valuePointer) (*logFile, error) {
vlog.filesLock.RLock()
defer vlog.filesLock.RUnlock()
ret, ok := vlog.filesMap[vp.Fid]
if !ok {
// log file has gone away, we can't do anything. Return.
return nil, fmt.Errorf("file with ID: %d not found", vp.Fid)
}
// Check for valid offset if we are reading from writable log.
maxFid := vlog.maxFid
// In read-only mode we don't need to check for writable offset as we are not writing anything.
// Moreover, this offset is not set in readonly mode.
if !vlog.opt.ReadOnly && vp.Fid == maxFid {
currentOffset := vlog.woffset()
if vp.Offset >= currentOffset {
return nil, fmt.Errorf(
"Invalid value pointer offset: %d greater than current offset: %d",
vp.Offset, currentOffset)
}
}
ret.lock.RLock()
return ret, nil
}
// Read reads the value log at a given location.
// TODO: Make this read private.
func (vlog *valueLog) Read(vp valuePointer, _ *y.Slice) ([]byte, func(), error) {
buf, lf, err := vlog.readValueBytes(vp)
// log file is locked so, decide whether to lock immediately or let the caller to
// unlock it, after caller uses it.
cb := vlog.getUnlockCallback(lf)
if err != nil {
return nil, cb, errView on GitHub (pinned to 2a001d466f)
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.
Example fix
// before: mixing a new SST backup with an older vlog file $ cp new.sst /data/badger/ && cp old-000005.vlog /data/badger/ // read: Invalid value pointer offset: 9500 greater than current offset: 8192 // after: restore a consistent snapshot $ rsync --archive snapshot@ts/ /data/badger/ # SSTs and vlogs from same checkpoint // and reduce crash tail risk opt.SyncWrites = true
Defensive patterns
Strategy: retry
Validate before calling
// Go: validate restore consistency — SST and vlog file timestamps should match
func restoreConsistent(snapshotDir, dataDir string) error {
sstT := modTimeFirst(snapshotDir, "*.sst")
vlogT := modTimeFirst(snapshotDir, "*.vlog")
if !sstT.Equal(vlogT) && sstT.Sub(vlogT).Abs() > time.Minute {
return errors.New("mixed vlog/SST generations — restore full snapshot")
}
return nil
} Type guard
func isInvalidVpOffset(err error) bool {
return err != nil && strings.Contains(err.Error(), "Invalid value pointer offset")
} Try / catch
item, err := txn.Get(key)
if err != nil && isInvalidVpOffset(err) {
// retry after rewriting the key to regenerate its value pointer
if rwErr := regenerateAndPut(key); rwErr != nil {
return rwErr
}
return txn.Get(key)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Unsynced writes + hard crash/power loss; disk corruption or partial vlog truncation; restoring an older vlog file alongside newer SSTs (file-set version mismatch).
Related errors
- Empty value: %+v
- Invalid read: Len: %d read at:[%d:%d]
- ErrNoRewrite
- ErrTruncateNeeded
- While setting banned keys: %w
AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05).
Data as JSON: /api/errors/00468b7eebe611cb.
Report an issue: GitHub.