vitessio/vitess · warning
stream send error: %v
Error message
stream send error: %v
What it means
During VStreamResults, resultstreamer.Stream sends the initial fields/Gtid response over the VStreamResults gRPC stream. If the send callback fails (client disconnected, context canceled, RPC broken), it is wrapped as 'stream send error: %v'. The stream cannot continue without a live consumer, so the error propagates back to StreamResults.
Source
Thrown at go/vt/vttablet/tabletserver/vstreamer/resultstreamer.go:98
if rotatedLog {
rs.vse.vstreamerFlushedBinlogs.Add(1)
}
if err != nil {
return err
}
// first call the callback with the fields
flds, err := conn.Fields()
if err != nil {
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
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Inspect the wrapped cause for the actual transport error (EOF, context canceled, connection refused).
- Restart the VStreamResults request from a known gtid once the consumer is healthy.
- Check connectivity/timeout settings between the consumer and the tablet (gRPC keepalives, LB idle timeouts).
- Retry with backoff — streams are resumable by design via the gtid; treat this as a transient stream failure unless the cause is deterministic.
Example fix
// before
resp, err := vstreamResults(ctx, tablet, query) // one-shot, dies on transient send error
// after
for attempt := 0; attempt < maxRetries; attempt++ {
resp, err := vstreamResults(ctx, tablet, query)
if err == nil || !isTransientStreamError(err) {
break
}
time.Sleep(backoff(attempt))
} Defensive patterns
Strategy: retry
Validate before calling
// before streaming, confirm the tablet is reachable and the stream target is serving
if err := tabletHealthCheck(ctx, tabletAlias); err != nil {
return fmt.Errorf("tablet not ready for VStreamResults: %w", err)
} Type guard
func isTransientStreamError(err error) bool {
s := err.Error()
return strings.Contains(s, "stream send error") &&
(strings.Contains(s, "context canceled") || strings.Contains(s, "EOF") ||
strings.Contains(s, "Unavailable") || strings.Contains(s, "Broken pipe"))
} Try / catch
err := streamVStreamResults(ctx, tablet, query, handler)
if err != nil {
if isTransientStreamError(err) {
return retryWithBackoff(ctx, func() error { return streamVStreamResults(ctx, tablet, query, handler) })
}
return fmt.Errorf("VStreamResults failed permanently: %w", err)
} Prevention
- Resume streams from the last received gtid instead of full re-snapshots
- Set gRPC keepalives and LB idle timeouts longer than expected stream duration
- Handle consumer restarts gracefully — treat send errors as resumable
- Avoid streaming huge snapshots without checkpointing progress
When it happens
Trigger: The VStreamResults client closes its connection or cancels its context while the tablet is streaming results; network interruption between vtctld/vtgate and the tablet mid-stream; the send callback returns a transport error on the initial Fields/Gtid response or during row sends.
Common situations: Consumer timeout or restart while streaming a large table snapshot; load balancer killing long-lived streams; tablet draining/restart during a VStreamResults call; client crash during MoveTables-style result streaming.
Related errors
- gRPC connection wait time exceeded
- ErrStreamClosed
- send reply error: %v
- error dialing binlog server: %v
- error received from Stream %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/e4bf5dad29ecf5d0.
Report an issue: GitHub.