vitessio/vitess · error
invalid state found for vdiff table %s for vdiff_id %d on ta
Error message
invalid state found for vdiff table %s for vdiff_id %d on tablet %s
What it means
initVDiffTables reads existing _vt.vdiff_table rows for each table. It expects 0 rows (insert a new one) or exactly 1 row (update row count). Finding more than one row for the same (vdiff_id, table_name) means corrupted/duplicated state, so it throws `invalid state found for vdiff table`.
Source
Thrown at go/vt/vttablet/tabletmanager/vdiff/workflow_differ.go:611
query, err = sqlparser.ParseAndBind(sqlNewVDiffTable,
sqltypes.Int64BindVariable(wd.ct.id),
sqltypes.StringBindVariable(tableName),
sqltypes.Int64BindVariable(tableRows),
)
if err != nil {
return err
}
} else if len(qr.Rows) == 1 {
query, err = sqlparser.ParseAndBind(sqlUpdateTableRows,
sqltypes.Int64BindVariable(tableRows),
sqltypes.Int64BindVariable(wd.ct.id),
sqltypes.StringBindVariable(tableName),
)
if err != nil {
return err
}
} else {
return fmt.Errorf("invalid state found for vdiff table %s for vdiff_id %d on tablet %s",
tableName, wd.ct.id, wd.ct.vde.thisTablet.Alias)
}
if _, err := dbClient.ExecuteFetch(query, 1); err != nil {
return err
}
}
return nil
}
// getSourceTopoServer returns the source topo server as for Mount+Migrate the
// source tablets will be in a different Vitess cluster with its own TopoServer.
func (wd *workflowDiffer) getSourceTopoServer() (*topo.Server, error) {
if wd.ct.externalCluster == "" {
return wd.ct.ts, nil
}
ctx, cancel := context.WithTimeout(wd.ct.vde.ctx, topo.RemoteOperationTimeout)
defer cancel()
return wd.ct.ts.OpenExternalVitessClusterServer(ctx, wd.ct.externalCluster)View on GitHub (pinned to 01a25a7d17)
Solutions
- Cancel any concurrent vdiffs on the workflow and ensure only one runs at a time
- Delete the duplicate rows from _vt.vdiff_table on the target primary (keep one row per table per vdiff id), then restart the vdiff
- Cleanest option: cancel the vdiff and start a fresh one so all table rows are recreated
- Check the Vitess version for known vdiff state bugs and upgrade if applicable
Example fix
// before (duplicates present) SELECT * FROM _vt.vdiff_table WHERE vdiff_id=1 AND table_name='t'; -- 2 rows // after cancel vdiff; delete dup rows (keep 1); re-run: DELETE vt1 FROM _vt.vdiff_table vt1 JOIN _vt.vdiff_table vt2 ON vt1.vdiff_id=vt2.vdiff_id AND vt1.table_name=vt2.table_name AND vt1.row_id > vt2.rowid WHERE vt1.vdiff_id=1;
Defensive patterns
Strategy: type-guard
Validate before calling
// before starting a vdiff, assert no duplicate table rows exist
qr, _ := dbClient.ExecuteFetch(fmt.Sprintf(`SELECT table_name, COUNT(*) c
FROM _vt.vdiff_table WHERE vdiff_id=%d GROUP BY table_name HAVING c>1`, id), -1)
if len(qr.Rows) > 0 { // duplicates: clean up or cancel/restart the vdiff } Type guard
func vdiffTableStateIsClean(dbClient binlogplayer.DBClient, vdiffID int64) bool {
qr, err := dbClient.ExecuteFetch(fmt.Sprintf(
`SELECT table_name, COUNT(*) c FROM _vt.vdiff_table WHERE vdiff_id=%d GROUP BY table_name HAVING c>1`, vdiffID), -1)
return err == nil && len(qr.Rows) == 0
} Try / catch
if err := wd.diff(ctx, dbClient); err != nil {
if strings.Contains(err.Error(), "invalid state found for vdiff table") {
return fmt.Errorf("duplicate _vt.vdiff_table rows; cancel vdiff, clean duplicates, rerun: %w", err)
}
return err
} Prevention
- Never run two vdiffs concurrently on the same workflow
- Don't manually insert/delete rows in _vt.vdiff_table
- Cancel a stuck vdiff before starting a new one
- Upgrade past known Vitess versions with vdiff state bugs
When it happens
Trigger: Duplicate rows in _vt.vdiff_table for the same vdiff id and table name — caused by concurrent vdiff operations on the same workflow, retried inserts without unique constraints being honored, or manual manipulation of _vt tables.
Common situations: Running two vdiffs simultaneously against the same workflow; a previously failed vdiff left duplicate rows; DBA manually inserted rows into _vt.vdiff_table; older Vitess version bug that allowed duplicates.
Related errors
- invalid state found for vdiff table %s (multiple records) fo
- too many vdiffs found (%d) for UUID %s keyspace %s and workf
- no state found for vdiff table %s for vdiff_id %d on tablet
- no vdiff table found for %s on tablet %v
- VDiff not implemented in vtcombo
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/ead05d3d0648469a.
Report an issue: GitHub.