vitessio/vitess · error
no state found for vdiff table %s for vdiff_id %d on tablet
Error message
no state found for vdiff table %s for vdiff_id %d on tablet %v
What it means
Before diffing a table, the differ loads the saved state row for (vdiff_id, table) from _vt.vdiff_table. If the query returns zero rows there is no prior state (last PK, counts, etc.) to continue from, so diff aborts with this error.
Source
Thrown at go/vt/vttablet/tabletmanager/vdiff/table_differ.go:544
}
defer dbClient.Close()
// We need to continue were we left off when appropriate. This can be an
// auto-retry on error, or a manual retry via the resume command.
// Otherwise the existing state will be empty and we start from scratch.
query, err := sqlparser.ParseAndBind(sqlGetVDiffTable,
sqltypes.Int64BindVariable(td.wd.ct.id),
sqltypes.StringBindVariable(td.table.Name),
)
if err != nil {
return nil, err
}
cs, err := dbClient.ExecuteFetch(query, -1)
if err != nil {
return nil, err
}
if len(cs.Rows) == 0 {
return nil, fmt.Errorf("no state found for vdiff table %s for vdiff_id %d on tablet %v",
td.table.Name, td.wd.ct.id, td.wd.ct.vde.thisTablet.Alias)
} else if len(cs.Rows) > 1 {
return nil, fmt.Errorf("invalid state found for vdiff table %s (multiple records) for vdiff_id %d on tablet %v",
td.table.Name, td.wd.ct.id, td.wd.ct.vde.thisTablet.Alias)
}
curState := cs.Named().Row()
mismatch := curState.AsBool("mismatch", false)
dr := &DiffReport{}
if rpt := curState.AsBytes("report", []byte("{}")); json.Valid(rpt) {
if err = json.Unmarshal(rpt, dr); err != nil {
return nil, err
}
}
dr.TableName = td.table.Name
// Scope executor goroutines to this single diff attempt, rather
// than surviving until the controller context is canceled.
execCtx, cancelExec := context.WithCancel(ctx)View on GitHub (pinned to 01a25a7d17)
Solutions
- Delete the vdiff and create a fresh one so state rows are properly inserted: vtctldclient vdiff ... delete all, then create.
- Verify rows exist: SELECT * FROM _vt.vdiff_table WHERE vdiff_id=<id> AND table_name='<t>'; on the tablet.
- Do not manually remove _vt.vdiff_table rows while a vdiff is active.
Example fix
// before DELETE FROM _vt.vdiff_table WHERE vdiff_id=7; // while vdiff 7 running // after vtctldclient vdiff --keyspace ks --workflow wf delete all vtctldclient vdiff --keyspace ks --workflow wf create // reinserts state
Defensive patterns
Strategy: validation
Validate before calling
var n int
_ := db.QueryRow("SELECT COUNT(*) FROM _vt.vdiff_table WHERE vdiff_id=? AND table_name=?", id, table).Scan(&n)
if n == 0 { recreateVDiff() } Try / catch
if err != nil && strings.Contains(err.Error(), "no state found for vdiff table") {
// state row missing; delete all + create a fresh vdiff
deleteAllVDiffs(workflow)
createVDiff(keyspace, workflow)
} Prevention
- Never DELETE from _vt.vdiff_table while a vdiff is active.
- Use 'vdiff delete all' for cleanup instead of manual row surgery.
- Verify _vt.vdiff_table rows exist after restoring a tablet.
- Don't mix vdiff ids from previous runs when resuming.
When it happens
Trigger: diff → table state query returns len(cs.Rows)==0 because the _vt.vdiff_table row for this vdiff id/table is missing — deleted manually, or the vdiff record was recreated with a new id while an old controller ran.
Common situations: Manual cleanup of _vt.vdiff_table while a vdiff runs; controller retry after the row was removed by 'vdiff delete all'; replica tablet with truncated/missing _vt.vdiff_table data.
Related errors
- no vdiff found for id %d on tablet %v
- invalid state found for vdiff table %s (multiple records) fo
- unable to create vdiff for UUID %s on tablet %s (%w)
- vdiff with UUID %s not found on tablet %s
- unable to %s vdiff for UUID %s as it was not found on tablet
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/864ccdb27f084241.
Report an issue: GitHub.