{"record":{"id":"10d7f5c9e2f0ea87","repo":"vitessio/vitess","slug":"row-stream-send-error-w","errorCode":null,"errorMessage":"row stream send error: %w","messagePattern":"row stream send error: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go","lineNumber":405,"sourceCode":"\t\t\tName:    rs.plan.Table.Fields[pk].Name,\n\t\t\tType:    rs.plan.Table.Fields[pk].Type,\n\t\t\tCharset: rs.plan.Table.Fields[pk].Charset,\n\t\t\tFlags:   rs.plan.Table.Fields[pk].Flags,\n\t\t}\n\t}\n\n\tcharsets := make([]collations.ID, len(rs.plan.Table.Fields))\n\tfor i, fld := range rs.plan.Table.Fields {\n\t\tcharsets[i] = collations.ID(fld.Charset)\n\t}\n\n\terr = safeSend(rs.ctx, &binlogdatapb.VStreamRowsResponse{\n\t\tFields:   rs.plan.fields(),\n\t\tPkfields: pkfields,\n\t\tGtid:     gtid,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"row stream send error: %w\", err)\n\t}\n\n\t// streamQuery sends heartbeats as long as it operates\n\theartbeatCtx, stopHeartbeats := context.WithCancel(rs.ctx)\n\tdefer stopHeartbeats()\n\theartbeatInterval := rowStreamertHeartbeatInterval\n\tgo func() {\n\t\theartbeatTicker := time.NewTicker(heartbeatInterval)\n\t\tdefer heartbeatTicker.Stop()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-heartbeatCtx.Done():\n\t\t\t\treturn\n\t\t\tcase <-heartbeatTicker.C:\n\t\t\t\t_ = safeSend(heartbeatCtx, &binlogdatapb.VStreamRowsResponse{Heartbeat: true})\n\t\t\t}\n\t\t}","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go#L387-L423","documentation":"The initial VStreamRowsResponse (fields, pk fields, gtid) could not be delivered because the underlying send function failed. safeSend returned an error that was not a context cancellation (those produce 'row stream ended'), so it is wrapped as 'row stream send error'.","triggerScenarios":"streamQuery's first safeSend of fields/pkfields/gtid fails — the send callback passed to Stream errors, typically because the receiving gRPC stream to the caller is broken.","commonSituations":"Network interruption between vtgate/vtctld and the tablet during copy phase start, receiver gone (workflow cancelled concurrently), gRPC stream reset.","solutions":["Check tablet logs for the underlying send error cause (broken pipe, connection reset) and inspect network/connectivity between the tablet and the VStream consumer.","Retry the VStream/workflow; copy-phase resumes from checkpoint.","If it recurs, verify the receiver (vtgate/vtctld) is healthy and that no proxy/load balancer is killing long-lived gRPC streams (idle timeouts)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := rowStream(ctx, ...)\nif err != nil && strings.Contains(err.Error(), \"row stream send error\") {\n    // underlying send failed (network/receiver gone): backoff and retry the stream\n    time.Sleep(backoff)\n    retryStream(ctx)\n}","preventionTips":["Monitor network stability between tablet and consumer","Avoid killing the receiver mid-copy; stop workflows before teardown","Configure LBs/proxies to allow long-lived gRPC streams","Use exponential backoff retries for transient send failures"],"tags":["vstreamer","rowstreamer","grpc","send-failure"],"backgroundTag":"grpc-stream-send-failure","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}