vitessio/vitess · error
cannot update vreplication table, affected %v rows
Error message
cannot update vreplication table, affected %v rows
What it means
Thrown by writeRecoveryPosition when the UPDATE of the _vt.vreplication row executes successfully but affects 0 rows instead of 1 — meaning no row exists for this player's uid. The player then rolls back the enclosing transaction (via the caller), so neither data nor position is committed.
Source
Thrown at go/vt/binlog/binlogplayer/binlog_player.go:531
// with it, and set ReplicationLagSeconds to now() - transaction_timestamp
// - otherwise (the statements are probably filtered out), we leave
// transaction_timestamp alone (keeping the old value), and we don't
// change ReplicationLagSeconds
func (blp *BinlogPlayer) writeRecoveryPosition(tx *binlogdatapb.BinlogTransaction) error {
position, err := DecodePosition(tx.EventToken.Position)
if err != nil {
return err
}
now := time.Now().Unix()
updateRecovery := GenerateUpdatePos(blp.uid, position, now, tx.EventToken.Timestamp, blp.blplStats.CopyRowCount.Get(), false)
qr, err := blp.exec(updateRecovery)
if err != nil {
return fmt.Errorf("error %v in writing recovery info %v", err, updateRecovery)
}
if qr.RowsAffected != 1 {
return fmt.Errorf("cannot update vreplication table, affected %v rows", qr.RowsAffected)
}
// Update position after successful write.
blp.position = position
blp.blplStats.SetLastPosition(blp.position)
if tx.EventToken.Timestamp != 0 {
blp.blplStats.ReplicationLagSeconds.Store(now - tx.EventToken.Timestamp)
}
return nil
}
func (blp *BinlogPlayer) setVReplicationState(state binlogdatapb.VReplicationWorkflowState, message string) error {
if message != "" {
blp.blplStats.History.Add(&StatsHistoryRecord{
Time: time.Now(),
Message: message,
})
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Check if the vreplication row still exists: `SELECT id, state FROM _vt.vreplication WHERE id=<uid>`; if deleted intentionally, stop the player — the workflow is gone.
- If deleted accidentally, recreate the workflow/stream to insert a new row and resync.
- Avoid deleting vreplication rows while streams are active; cancel the workflow first and wait for state=Stopped.
- Investigate concurrent automation (shard pruning scripts) racing with active streams.
Example fix
// before: deleting row while stream is live // DELETE FROM _vt.vreplication WHERE id=1; -- row gone, update hits 0 rows // after: stop the stream first, then remove // vtctldclient VReplicationExec <keyspace> "update _vt.vreplication set state='Stopped' where id=1" // # then delete after the player exits
Defensive patterns
Strategy: validation
Validate before calling
// before each stream start (and periodically), confirm the row exists
var n int
if err := targetDB.QueryRow(
"SELECT COUNT(*) FROM _vt.vreplication WHERE id = ?", uid,
).Scan(&n); err != nil || n != 1 {
return fmt.Errorf("vreplication row id=%d missing; workflow was removed or never created", uid)
} Try / catch
err := binlogplayer.ApplyBinlogEvents(ctx, blp)
if err != nil && strings.Contains(err.Error(), "cannot update vreplication table") {
// row deleted concurrently — do NOT blindly restart; check workflow intent
log.Error("_vt.vreplication row vanished mid-stream; workflow was likely deleted")
return err
} Prevention
- Stop the workflow (state='Stopped') and wait for the player to exit before deleting rows
- Audit automation scripts that prune _vt.vreplication rows for races with active streams
- Use vtctldclient workflow commands rather than raw SQL for lifecycle changes
When it happens
Trigger: The _vt.vreplication row with id=blp.uid was deleted concurrently (stream cancelled externally, workflow removed) while the player was still applying events, or the row was never inserted for this uid.
Common situations: Operator ran `vtctldclient Workflow ... delete` or VReplicationExec delete while the stream was mid-transaction; target keyspace re-sharded/pruned old vreplication rows; race between workflow removal and tablet shutdown.
Related errors
- error %v in writing recovery info %v
- %s: stream %d position: %s does not match %s
- value out of range
- both atomic copy and partial mode cannot be specified for th
- invalid workflow
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/62b55f3960eb9e66.
Report an issue: GitHub.