{"record":{"id":"d47520e44b9db11c","repo":"dgraph-io/dgraph","slug":"restorerequest-must-have-a-valid-restorets","errorCode":null,"errorMessage":"RestoreRequest must have a valid restoreTs","messagePattern":"RestoreRequest must have a valid restoreTs","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"worker/restore_map.go","lineNumber":744,"sourceCode":"\tdropAttr      map[string]struct{}\n\tdropNs        map[uint64]struct{}\n}\n\n// we create MAP files each of a limited size and write sorted data into it. We may end up\n// creating many such files. Then we take all of these MAP files and read part of the data\n// from each file, sort all of this data and then use streamwriter to write the sorted data\n// into pstore badger. We store some sort of partition keys in the MAP file in the beginning\n// of the file. The partition keys are just intermediate keys among the entries that we store\n// in the map file. When we read data during reduce, we read in the chunks of these partition\n// keys, meaning from one partition key to the next partition key. I am not sure if there is a\n// value in having these partition keys. Maybe, we can live without them.\nfunc RunMapper(req *pb.RestoreRequest, mapDir string) (*mapResult, error) {\n\turi, err := url.Parse(req.Location)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif req.RestoreTs == 0 {\n\t\treturn nil, errors.New(\"RestoreRequest must have a valid restoreTs\")\n\t}\n\n\tcreds := getCredentialsFromRestoreRequest(req)\n\th, err := NewUriHandler(uri, creds)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmanifests, err := getManifestsToRestore(h, uri, req)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"cannot retrieve manifests\")\n\t}\n\tglog.Infof(\"Got %d backups to restore \", len(manifests))\n\n\tcfg, err := getEncConfig(req)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"unable to get encryption config\")\n\t}","sourceCodeStart":726,"sourceCodeEnd":762,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/worker/restore_map.go#L726-L762","documentation":"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.","triggerScenarios":"Calling RunMapper (directly or via runExportBackup, handleRestoreProposal, RunOfflineRestore) with a pb.RestoreRequest whose RestoreTs field was never set (defaults to 0).","commonSituations":"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.","solutions":["Set req.RestoreTs from the backup manifest's value (manifest.RestoreTs or BackupTs) before calling RunMapper.","If using dgraph restore CLI/Alpha RPC, ensure the input manifest is loaded so RestoreTs is populated rather than built by hand.","Verify with a nil/zero check on the request before invoking RunMapper to fail fast with a clearer message."],"exampleFix":"// before\nreq := &pb.RestoreRequest{Location: loc}\nres, err := worker.RunMapper(req, mapDir)\n// after\nreq := &pb.RestoreRequest{Location: loc, RestoreTs: manifest.RestoreTs}\nif req.RestoreTs == 0 {\n    return errors.New(\"manifest has no RestoreTs; cannot restore\")\n}\nres, err := worker.RunMapper(req, mapDir)","handlingStrategy":"validation","validationCode":"if req == nil || req.RestoreTs == 0 {\n    return errors.New(\"RestoreRequest.RestoreTs must be set from the backup manifest\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always populate RestoreTs from the loaded manifest, never hardcode 0","Add a pre-flight check on RestoreRequest before calling worker.RunMapper","Load the manifest via the same library that produced the backup"],"tags":["dgraph","restore","request-validation","config"],"backgroundTag":"missing-required-request-field","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}