vitessio/vitess · error

send reply error: %v

Error message

send reply error: %v

What it means

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.

Source

Thrown at go/vt/binlog/binlog_streamer.go:285

			log.Error(fmt.Sprintf("BEGIN in binlog stream while still in another transaction; dropping %d statements: %v", len(statements), statements))
			binlogStreamerErrors.Add("ParseEvents", 1)
		}
		statements = make([]FullBinlogStatement, 0, 10)
		autocommit = false
	}
	// A commit can be triggered either by a COMMIT query, or by an XID_EVENT.
	// Statements that aren't wrapped in BEGIN/COMMIT are committed immediately.
	commit := func(timestamp uint32) error {
		if int64(timestamp) >= bls.timestamp {
			eventToken := &querypb.EventToken{
				Timestamp: int64(timestamp),
				Position:  replication.EncodePosition(pos),
			}
			if err = bls.sendTransaction(eventToken, statements); err != nil {
				if err == io.EOF {
					return ErrClientEOF
				}
				return fmt.Errorf("send reply error: %v", err)
			}
		}
		statements = nil
		autocommit = true
		return nil
	}

	// Parse events.
	for {
		var ev mysql.BinlogEvent
		var ok bool

		select {
		case ev, ok = <-events:
			if !ok {
				// events channel has been closed, which means the connection died.
				log.Info("reached end of binlog event stream")
				return pos, ErrServerEOF

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Inspect the wrapped inner error to find why sendTransaction failed
  2. Reconnect the binlog consumer and restart the stream from the last known position
  3. Check network stability / RPC timeouts between vttablet and the client
  4. If the client is gone, treat as ErrClientEOF-like behavior: stop streaming and let the service restart on demand
Defensive patterns

Strategy: retry

Validate before calling

// ensure the consumer's RPC connection is alive before streaming
if err := clientConn.Ping(ctx); err != nil {
	// reconnect the consumer first
}

Try / catch

if err := streamer.Stream(ctx); err != nil {
	if strings.Contains(err.Error(), "send reply error") {
		// consumer failed: reconnect consumer, resume stream from last EventToken position
	}
}

Prevention

When it happens

Trigger: 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.

Common situations: UpdateStream client disconnected abnormally; network interruption between vttablet and the binlog consumer; downstream vreplication worker crashed while applying transactions.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/45216e6a3d8341ce. Report an issue: GitHub.