dgraph-io/dgraph · error
failed to send 'done' signal for group [%d]: %w
Error message
failed to send 'done' signal for group [%d]: %w
What it means
Returned by streamBadger when sending the final Done packet fails (non-EOF). This packet tells the server the group's snapshot stream is complete; without a successful send the server treats the transfer as incomplete and will not finalize the snapshot.
Source
Thrown at dgraph/cmd/dgraphimport/import_client.go:242
if _, err := out.Recv(); err != nil {
return fmt.Errorf("failed to receive response for group ID [%v] from the server: %w", groupId, err)
}
glog.Infof("[import] Group [%v]: Received ACK for sending data chunk", groupId)
return nil
}
// Execute the stream process
if err := stream.Orchestrate(ctx); err != nil {
return fmt.Errorf("stream orchestration failed for group [%v]: %w, badger path: %s", groupId, err, ps.Opts().Dir)
}
// Send the final 'done' signal to mark completion
glog.Infof("[import] Sending completion signal for group [%d]", groupId)
done := &api.StreamPacket{Done: true}
if err := out.Send(&api.StreamExtSnapshotRequest{Pkt: done}); err != nil && !errors.Is(err, io.EOF) {
return fmt.Errorf("failed to send 'done' signal for group [%d]: %w", groupId, err)
}
for {
if ctx.Err() != nil {
return ctx.Err()
}
resp, err := out.Recv()
if errors.Is(err, io.EOF) {
return fmt.Errorf("server closed stream before Finish=true for group [%d]", groupId)
}
if err != nil {
return fmt.Errorf("failed to receive final response for group ID [%v] from the server: %w", groupId, err)
}
if resp.Finish {
glog.Infof("[import] Group [%v]: Received final Finish=true", groupId)
break
}
glog.Infof("[import] Group [%v]: Waiting for Finish=true, got interim ACK", groupId)View on GitHub (pinned to 759e242be6)
Solutions
- Check whether the done Send failed because the stream was already dead — inspect earlier gRPC errors and server logs.
- Re-run the import for the affected group; a missing done signal means the server never finalized.
- Fix stream stability (keepalive, LB timeouts) so the connection survives the whole transfer.
- Verify all groups report completion server-side after the import.
- Protect the transfer with a context sized for the dataset, not a default short deadline.
Example fix
// before
if err := out.Send(&api.StreamExtSnapshotRequest{Pkt: done}); err != nil && !errors.Is(err, io.EOF) {
return fmt.Errorf("failed to send 'done' signal for group [%d]: %w", groupId, err)
}
// after
if err := out.Send(&api.StreamExtSnapshotRequest{Pkt: done}); err != nil && !errors.Is(err, io.EOF) {
return fmt.Errorf("failed to send 'done' signal for group [%d] (transfer incomplete, will need re-run): %w", groupId, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
select {
case <-ctx.Done():
return fmt.Errorf("context ended before done-signal; extend deadline: %w", ctx.Err())
default:
} Type guard
func streamAlreadyDead(err error) bool {
s, ok := status.FromError(err)
return ok && (s.Code() == codes.Unavailable || s.Code() == codes.Canceled)
} Try / catch
if err := out.Send(&api.StreamExtSnapshotRequest{Pkt: done}); err != nil && !errors.Is(err, io.EOF) {
if streamAlreadyDead(err) {
return fmt.Errorf("stream died before completion for group %d; full re-import required: %w", groupId, err)
}
return fmt.Errorf("failed to send 'done' signal for group [%d]: %w", groupId, err)
} Prevention
- Keep the connection alive for the entire transfer (keepalive, no LB drops).
- Avoid Alpha restarts during imports (k8s PDBs, maintenance windows).
- Verify server-side completion for every group after import.
- Reserve headroom in the context deadline for the final handshake.
When it happens
Trigger: The gRPC stream already broke during data transfer (server crash, connection reset) so the done Send fails; server closed its side after an earlier error; context cancelled at the very end of a long transfer.
Common situations: Import that 'almost finished' but the Alpha restarted or was OOM-killed; LB/proxy dropping the long-lived stream just before completion; cluster churn (leader change) invalidating the stream.
Related errors
- failed to start external snapshot stream for group %d: %w
- failed to send request for group ID [%v] to the server: %w
- failed to receive response for group ID [%v] from the server
- failed to send data chunk: %w
- failed to disable drain mode: %v
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/6062435f886544e9.
Report an issue: GitHub.