{"record":{"id":"45216e6a3d8341ce","repo":"vitessio/vitess","slug":"send-reply-error-v","errorCode":null,"errorMessage":"send reply error: %v","messagePattern":"send reply error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/binlog/binlog_streamer.go","lineNumber":285,"sourceCode":"\t\t\tlog.Error(fmt.Sprintf(\"BEGIN in binlog stream while still in another transaction; dropping %d statements: %v\", len(statements), statements))\n\t\t\tbinlogStreamerErrors.Add(\"ParseEvents\", 1)\n\t\t}\n\t\tstatements = make([]FullBinlogStatement, 0, 10)\n\t\tautocommit = false\n\t}\n\t// A commit can be triggered either by a COMMIT query, or by an XID_EVENT.\n\t// Statements that aren't wrapped in BEGIN/COMMIT are committed immediately.\n\tcommit := func(timestamp uint32) error {\n\t\tif int64(timestamp) >= bls.timestamp {\n\t\t\teventToken := &querypb.EventToken{\n\t\t\t\tTimestamp: int64(timestamp),\n\t\t\t\tPosition:  replication.EncodePosition(pos),\n\t\t\t}\n\t\t\tif err = bls.sendTransaction(eventToken, statements); err != nil {\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\treturn ErrClientEOF\n\t\t\t\t}\n\t\t\t\treturn fmt.Errorf(\"send reply error: %v\", err)\n\t\t\t}\n\t\t}\n\t\tstatements = nil\n\t\tautocommit = true\n\t\treturn nil\n\t}\n\n\t// Parse events.\n\tfor {\n\t\tvar ev mysql.BinlogEvent\n\t\tvar ok bool\n\n\t\tselect {\n\t\tcase ev, ok = <-events:\n\t\t\tif !ok {\n\t\t\t\t// events channel has been closed, which means the connection died.\n\t\t\t\tlog.Info(\"reached end of binlog event stream\")\n\t\t\t\treturn pos, ErrServerEOF","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/binlog/binlog_streamer.go#L267-L303","documentation":"parseEvents wraps a failure returned by the sendTransaction callback (minus io.EOF, which becomes ErrClientEOF). This means the consumer of the binlog stream failed to receive or process a committed transaction. The original consumer error is embedded in the message.","triggerScenarios":"During Stream/parseEvents, a transaction commit is dispatched to the registered sendTransaction function (the binlog service's client handler, e.g. UpdateStream RPC delivery) and that function returns a non-EOF error — e.g. the gRPC client connection broke, or the downstream writer returned an error.","commonSituations":"UpdateStream client disconnected abnormally; network interruption between vttablet and the binlog consumer; downstream vreplication worker crashed while applying transactions.","solutions":["Inspect the wrapped inner error to find why sendTransaction failed","Reconnect the binlog consumer and restart the stream from the last known position","Check network stability / RPC timeouts between vttablet and the client","If the client is gone, treat as ErrClientEOF-like behavior: stop streaming and let the service restart on demand"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// ensure the consumer's RPC connection is alive before streaming\nif err := clientConn.Ping(ctx); err != nil {\n\t// reconnect the consumer first\n}","typeGuard":null,"tryCatchPattern":"if err := streamer.Stream(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"send reply error\") {\n\t\t// consumer failed: reconnect consumer, resume stream from last EventToken position\n\t}\n}","preventionTips":["Make the sendTransaction consumer resilient (buffer/reconnect internally)","Monitor consumer RPC connections","Resume streams from the last acknowledged EventToken position","Avoid long-lived streams over unstable network links without keepalives"],"tags":["binlog","rpc","streaming","network"],"backgroundTag":"stream-send-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}