dgraph-io/dgraph · error
nil restore request
Error message
nil restore request
What it means
Returned by handleRestoreProposal (worker/online_restore.go:201) when the Restore proposal carried through Raft has a nil RestoreRequest. The proposal is applied on every node of the group via applyCommitted, and this internal invariant guard means the proposal payload was empty or corrupted rather than a user error.
Source
Thrown at worker/online_restore.go:201
// We should wait to ensure that we have seen all the updates until the StartTs
// of this restore transaction.
if err := posting.Oracle().WaitForTs(ctx, req.RestoreTs); err != nil {
return nil, errors.Wrapf(err, "cannot wait for restore ts %d", req.RestoreTs)
}
glog.Infof("Proposing restore request")
err := groups().Node.proposeAndWait(ctx, &pb.Proposal{Restore: req})
if err != nil {
return &emptyRes, errors.Wrapf(err, errRestoreProposal)
}
return &emptyRes, nil
}
// TODO(DGRAPH-1232): Ensure all groups receive the restore proposal.
func handleRestoreProposal(ctx context.Context, req *pb.RestoreRequest, pidx uint64) error {
if req == nil {
return errors.Errorf("nil restore request")
}
// This is a minor inconvenience while using the incremental restore API that
// when incrementalFrom is set to 1, we throw an error back. The restore API
// takes two backup numbers incrementalFrom & backupNum and restores all the
// backups including both the ends, i.e. following set notation all the backups
// in the set [incrementalFrom, backupNum] are restored. This should work fine
// when incrementalFrom is set to 1 which is a full backup.
if req.IncrementalFrom == 1 {
req.IncrementalFrom = 0
}
// Clean up the cluster if it is a full backup restore.
if req.IncrementalFrom == 0 {
// Drop all the current data. This also cancels all existing transactions.
dropProposal := pb.Proposal{
Mutations: &pb.Mutations{
GroupId: req.GroupId,View on GitHub (pinned to 759e242be6)
Solutions
- Verify all Alphas in the cluster run the same Dgraph version and finish any rolling upgrade before restoring.
- Retry the restore; a transient decode issue should not recur on a healthy, homogeneous cluster.
- Collect Alpha logs around the proposal index and report upstream if it reproduces on a single-version cluster.
Defensive patterns
Strategy: validation
Validate before calling
// Ensure homogeneous binary versions before proposing restores // (run on every Alpha) dgraph version --full # all nodes must match exactly
Prevention
- Keep all cluster nodes on the exact same Dgraph version.
- Complete rolling upgrades fully before issuing restore proposals.
- Do not construct pb.Proposal messages manually; use the restore API.
- If reproducible on a homogeneous cluster, file an upstream bug with logs.
When it happens
Trigger: A pb.Proposal with Restore field unset is proposed to the Raft group; a serialization/upgrade mismatch between node versions causes the Restore field to decode as nil.
Common situations: Rolling upgrades where an older/newer Dgraph binary decodes the proposal differently; custom tooling or tests proposing malformed proposals; memory corruption bugs in the proposal path.
Related errors
- StartTs must be provided
- cannot propose restore request
- unable to reach quorum
- I am not the Zero leader
- while leasing txn timestamp. Id: %+v
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/59be83e785d719ce.
Report an issue: GitHub.