dgraph-io/dgraph · error

UpdateExtSnapshotStreamingStateRequest must not be nil

Error message

UpdateExtSnapshotStreamingStateRequest must not be nil

What it means

UpdateExtSnapshotStreamingState validates its request before proposing it to the Raft group. A nil *api.UpdateExtSnapshotStreamingStateRequest is rejected outright with this error because there is no state change to apply.

Source

Thrown at worker/import.go:459

		// Normal data chunk: send -> wait ack -> send upstream ack.
		if err := out.Send(&api.StreamExtSnapshotRequest{Pkt: req.Pkt}); err != nil {
			return fmt.Errorf("send data downstream(%d): %w", groupId, err)
		}
		if _, err := out.Recv(); err != nil {
			return fmt.Errorf("ack data downstream(%d): %w", groupId, err)
		}
		if err := in.Send(&api.StreamExtSnapshotResponse{}); err != nil {
			return fmt.Errorf("send ack upstream: %w", err)
		}

	}
}

func (w *grpcWorker) UpdateExtSnapshotStreamingState(ctx context.Context,
	req *api.UpdateExtSnapshotStreamingStateRequest) (*pb.Status, error) {
	if req == nil {
		return nil, errors.New("UpdateExtSnapshotStreamingStateRequest must not be nil")
	}

	if req.Start && req.Finish {
		return nil, errors.New("UpdateExtSnapshotStreamingStateRequest cannot have both Start and Finish set to true")
	}

	glog.Infof("[import] Applying import mode proposal: %+v", req)
	err := groups().Node.proposeAndWait(ctx, &pb.Proposal{ExtSnapshotState: req})

	return &pb.Status{}, err
}

// StreamExtSnapshot handles the stream of key-value pairs sent from proxy alpha.
// It receives a Forward flag from the stream to determine if the current node is the leader.
// If the node is the leader (Forward is true), it streams the data to its followers.
// Otherwise, it simply writes the data to BadgerDB and flushes it.
func (w *grpcWorker) StreamExtSnapshot(stream pb.Worker_StreamExtSnapshotServer) error {
	glog.Info("[import] trying to update the import mode to false")

View on GitHub (pinned to 759e242be6)

Solutions

  1. Always pass a non-nil &api.UpdateExtSnapshotStreamingStateRequest{} with Start or Finish set.
  2. Check the caller that builds the request and initialize it.
  3. If using a generic client wrapper, ensure it does not drop an empty-but-intended message.

Example fix

// before
resp, err := wc.UpdateExtSnapshotStreamingState(ctx, nil)
// after
req := &api.UpdateExtSnapshotStreamingStateRequest{Start: true}
resp, err := wc.UpdateExtSnapshotStreamingState(ctx, req)
Defensive patterns

Strategy: validation

Validate before calling

if req == nil {
    return errors.New("UpdateExtSnapshotStreamingStateRequest must be initialized before calling")
}

Type guard

func validStateReq(req *api.UpdateExtSnapshotStreamingStateRequest) bool {
    return req != nil
}

Try / catch

if _, err := wc.UpdateExtSnapshotStreamingState(ctx, req); err != nil {
    if strings.Contains(err.Error(), "must not be nil") { /* fix caller: build request */ }
}

Prevention

When it happens

Trigger: Calling the gRPC Worker.UpdateExtSnapshotStreamingState API (directly or via a client) with a nil request message, e.g. constructing the call programmatically without instantiating the request struct.

Common situations: Hand-written gRPC client code passing nil; a wrapper/SDK forwarding an unset message; tests invoking the worker method directly with nil.

Related errors


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