vitessio/vitess · info
stream ended
Error message
stream ended: %v
What it means
ResultStreamer.Stream returns this when its context is cancelled or times out while streaming rows for a table copy. It is the normal termination signal when the caller (e.g. VReplication workflow) stops or times out the stream, wrapped with the context error for diagnosis.
Solutions
- If the stream should have completed, check the wrapped ctx.Err(): DeadlineExceeded means increase the caller's timeout, Canceled means something stopped it (workflow cancel, tablet shutdown).
- Inspect VReplication workflow logs (vtctld / workflow logs) to see who cancelled the context; treat 'context canceled' at end of copy as expected shutdown, not data loss.
- If streams die repeatedly mid-copy, check tablet liveness/memory (OOM kills cancel contexts) and restart the workflow; copy phase resumes from lastpk.
- Retry the VStream; copy-phase streams are restartable and resume from the last primary-key checkpoint.
Defensive patterns
Strategy: retry
Try / catch
err := vstreamer.Stream(...)
if err != nil {
if errors.Is(err, context.Canceled) {
// expected shutdown; do not alert
} else if errors.Is(err, context.DeadlineExceeded) {
// increase timeout / retry with larger budget
}
} Prevention
- Use generous timeouts for copy-phase streams; large tables can stream for hours
- Treat context.Canceled at workflow stop as normal
- Monitor tablet memory to avoid OOM-induced cancellations
- Rely on lastpk checkpointing to resume rather than restarting from scratch
When it happens
Trigger: rs.ctx.Done() fires during the streaming loop — parent context cancelled, deadline exceeded, or tablet shutting down while ResultStreamer.Stream is running via StreamResults.
Common situations: VReplication workflow cancellation or move-tables completion, tablet restart during copy phase, context deadline from a caller timeout, vtctld cancelling a workflow.
Related errors
- row stream ended
- stream needs a position or a table to copy
- unsupported
- VStreamer is not open
- VStreamer is not open
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/bb96a47bff2ab182.
Report an issue: GitHub.
Appendix: source
Thrown at go/vt/vttablet/tabletserver/vstreamer/resultstreamer.go:108
return err
}
err = rs.send(&binlogdatapb.VStreamResultsResponse{
Fields: flds,
Gtid: gtid,
})
if err != nil {
return fmt.Errorf("stream send error: %v", err)
}
response := &binlogdatapb.VStreamResultsResponse{}
byteCount := 0
loggerName := fmt.Sprintf("%s (%v)", rs.vse.GetTabletInfo(), rs.tableName)
logger := logutil.NewThrottledLogger(loggerName, throttledLoggerInterval)
for {
select {
case <-rs.ctx.Done():
return fmt.Errorf("stream ended: %v", rs.ctx.Err())
default:
}
// check throttler.
if _, ok := rs.vse.throttlerClient.ThrottleCheckOKOrWaitAppName(rs.ctx, throttlerapp.ResultStreamerName); !ok {
logger.Infof("throttled.")
continue
}
row, err := conn.FetchNext(nil)
if err != nil {
return err
}
if row == nil {
break
}
response.Rows = append(response.Rows, sqltypes.RowToProto3(row))
for _, s := range row {View on GitHub (pinned to 01a25a7d17)