dgraph-io/badger · error

Backup: Item Version: %d less than sinceTs: %d

Error message

Backup: Item Version: %d less than sinceTs: %d

What it means

During badger backup (StreamBackup/Backup), when collecting all versions of a key whose version must be >= sinceTs, an item with a version lower than sinceTs is encountered, which would corrupt the incremental-backup contract; the library aborts with this error.

Source

Thrown at backup.go:64

// Backup dumps a protobuf-encoded list of all entries in the database into the
// given writer, that are newer than or equal to the specified version. It returns a
// timestamp(version) indicating the version of last entry that was dumped, which
// after incrementing by 1 can be passed into a later invocation to generate an
// incremental dump of entries that have been added/modified since the last
// invocation of Stream.Backup().
//
// This can be used to backup the data in a database at a given point in time.
func (stream *Stream) Backup(w io.Writer, since uint64) (uint64, error) {
	stream.KeyToList = func(key []byte, itr *Iterator) (*pb.KVList, error) {
		list := &pb.KVList{}
		a := itr.Alloc
		for ; itr.Valid(); itr.Next() {
			item := itr.Item()
			if !bytes.Equal(item.Key(), key) {
				return list, nil
			}
			if item.Version() < since {
				return nil, fmt.Errorf("Backup: Item Version: %d less than sinceTs: %d",
					item.Version(), since)
			}

			var valCopy []byte
			if !item.IsDeletedOrExpired() {
				// No need to copy value, if item is deleted or expired.
				err := item.Value(func(val []byte) error {
					valCopy = a.Copy(val)
					return nil
				})
				if err != nil {
					stream.db.opt.Errorf("Key [%x, %d]. Error while fetching value [%v]\n",
						item.Key(), item.Version(), err)
					return nil, err
				}
			}

			// clear txn bits

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Always take sinceTs from the previous successful backup of the SAME database (badger tracks it via the yield item / backup metadata), not from another instance
  2. For a full backup, do not set SinceTs (use zero/default so all versions are allowed)
  3. If the DB was restored from a mixture of sources, take a fresh full backup to re-establish a consistent baseline
  4. Verify no manual timestamp/version manipulation occurred (DiscardTs / DropAll interplay)

Example fix

// before: incremental with foreign sinceTs
_, err := db.Backup(w, sinceTsFromOtherDB)
// after: full backup, then chain incrementals from this DB's own markers
sinceTs := uint64(0) // full backup baseline
_, err := db.Backup(w, sinceTs)
Defensive patterns

Strategy: validation

Validate before calling

// only use a sinceTs produced by a prior backup of the SAME DB
// full backup:
n, err := db.Backup(w, 0)
// incremental:
n, err := db.Backup(w, lastBackupTs) // lastBackupTs from this DB's own backup stream

Type guard

func saneSinceTs(since uint64, knownMax uint64) bool {
    return since == 0 || since <= knownMax
}

Try / catch

if _, err := db.Backup(w, sinceTs); err != nil {
    if strings.Contains(err.Error(), "less than sinceTs") {
        log.Error("sinceTs not from this DB's backup chain; falling back to full backup")
        _, err = db.Backup(w, 0)
    }
}

Prevention

When it happens

Trigger: Running an incremental backup with a since timestamp while the iterator sees versions below that timestamp — typically when the sinceTs passed does not correspond to a real snapshot boundary of this DB, or the iteration spans keys whose versions are not monotonically newer than sinceTs (e.g. restores mixing datasets, or a sinceTs restored from another instance).

Common situations: Incremental backup chains where sinceTs was taken from a different DB or after a restore; using a timestamp smaller than existing data versions due to clock or manual manipulation; passing 0/incorrect values into Backup(ws, sinceTs) semantics via Opts.SinceTs.

Related errors


AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05). Data as JSON: /api/errors/408bf364dd51c190. Report an issue: GitHub.