dgraph-io/dgraph · error

RestoreRequest must have a valid restoreTs

Error message

RestoreRequest must have a valid restoreTs

What it means

RunMapper validates the RestoreRequest before starting the map phase and refuses to run when req.RestoreTs is zero. RestoreTs is the timestamp (restore-to point) the restored keyspace must carry; without it the restore cannot construct valid postings, so the request is rejected immediately.

Source

Thrown at worker/restore_map.go:744

	dropAttr      map[string]struct{}
	dropNs        map[uint64]struct{}
}

// we create MAP files each of a limited size and write sorted data into it. We may end up
// creating many such files. Then we take all of these MAP files and read part of the data
// from each file, sort all of this data and then use streamwriter to write the sorted data
// into pstore badger. We store some sort of partition keys in the MAP file in the beginning
// of the file. The partition keys are just intermediate keys among the entries that we store
// in the map file. When we read data during reduce, we read in the chunks of these partition
// keys, meaning from one partition key to the next partition key. I am not sure if there is a
// value in having these partition keys. Maybe, we can live without them.
func RunMapper(req *pb.RestoreRequest, mapDir string) (*mapResult, error) {
	uri, err := url.Parse(req.Location)
	if err != nil {
		return nil, err
	}
	if req.RestoreTs == 0 {
		return nil, errors.New("RestoreRequest must have a valid restoreTs")
	}

	creds := getCredentialsFromRestoreRequest(req)
	h, err := NewUriHandler(uri, creds)
	if err != nil {
		return nil, err
	}

	manifests, err := getManifestsToRestore(h, uri, req)
	if err != nil {
		return nil, errors.Wrapf(err, "cannot retrieve manifests")
	}
	glog.Infof("Got %d backups to restore ", len(manifests))

	cfg, err := getEncConfig(req)
	if err != nil {
		return nil, errors.Wrapf(err, "unable to get encryption config")
	}

View on GitHub (pinned to 759e242be6)

Solutions

  1. Set req.RestoreTs from the backup manifest's value (manifest.RestoreTs or BackupTs) before calling RunMapper.
  2. If using dgraph restore CLI/Alpha RPC, ensure the input manifest is loaded so RestoreTs is populated rather than built by hand.
  3. Verify with a nil/zero check on the request before invoking RunMapper to fail fast with a clearer message.

Example fix

// before
req := &pb.RestoreRequest{Location: loc}
res, err := worker.RunMapper(req, mapDir)
// after
req := &pb.RestoreRequest{Location: loc, RestoreTs: manifest.RestoreTs}
if req.RestoreTs == 0 {
    return errors.New("manifest has no RestoreTs; cannot restore")
}
res, err := worker.RunMapper(req, mapDir)
Defensive patterns

Strategy: validation

Validate before calling

if req == nil || req.RestoreTs == 0 {
    return errors.New("RestoreRequest.RestoreTs must be set from the backup manifest")
}

Prevention

When it happens

Trigger: Calling RunMapper (directly or via runExportBackup, handleRestoreProposal, RunOfflineRestore) with a pb.RestoreRequest whose RestoreTs field was never set (defaults to 0).

Common situations: Constructing a RestoreRequest programmatically for offline restore or export-backup tooling and forgetting to copy RestoreTs from the backup manifest; older clients or tooling that predate the RestoreTs field leaving it unset.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/d47520e44b9db11c. Report an issue: GitHub.