{"record":{"id":"bb96a47bff2ab182","repo":"vitessio/vitess","slug":"stream-ended-v","errorCode":null,"errorMessage":"stream ended: %v","messagePattern":"stream ended: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"go/vt/vttablet/tabletserver/vstreamer/resultstreamer.go","lineNumber":108,"sourceCode":"\t\treturn err\n\t}\n\n\terr = rs.send(&binlogdatapb.VStreamResultsResponse{\n\t\tFields: flds,\n\t\tGtid:   gtid,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"stream send error: %v\", err)\n\t}\n\n\tresponse := &binlogdatapb.VStreamResultsResponse{}\n\tbyteCount := 0\n\tloggerName := fmt.Sprintf(\"%s (%v)\", rs.vse.GetTabletInfo(), rs.tableName)\n\tlogger := logutil.NewThrottledLogger(loggerName, throttledLoggerInterval)\n\tfor {\n\t\tselect {\n\t\tcase <-rs.ctx.Done():\n\t\t\treturn fmt.Errorf(\"stream ended: %v\", rs.ctx.Err())\n\t\tdefault:\n\t\t}\n\n\t\t// check throttler.\n\t\tif _, ok := rs.vse.throttlerClient.ThrottleCheckOKOrWaitAppName(rs.ctx, throttlerapp.ResultStreamerName); !ok {\n\t\t\tlogger.Infof(\"throttled.\")\n\t\t\tcontinue\n\t\t}\n\n\t\trow, err := conn.FetchNext(nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif row == nil {\n\t\t\tbreak\n\t\t}\n\t\tresponse.Rows = append(response.Rows, sqltypes.RowToProto3(row))\n\t\tfor _, s := range row {","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletserver/vstreamer/resultstreamer.go#L90-L126","documentation":"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.","triggerScenarios":"rs.ctx.Done() fires during the streaming loop — parent context cancelled, deadline exceeded, or tablet shutting down while ResultStreamer.Stream is running via StreamResults.","commonSituations":"VReplication workflow cancellation or move-tables completion, tablet restart during copy phase, context deadline from a caller timeout, vtctld cancelling a workflow.","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."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := vstreamer.Stream(...)\nif err != nil {\n    if errors.Is(err, context.Canceled) {\n        // expected shutdown; do not alert\n    } else if errors.Is(err, context.DeadlineExceeded) {\n        // increase timeout / retry with larger budget\n    }\n}","preventionTips":["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"],"tags":["vstreamer","context-canceled","vreplication"],"backgroundTag":"context-canceled-during-stream","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}