vitessio/vitess · error

too many vdiffs found (%d) for UUID %s keyspace %s and workf

Error message

too many vdiffs found (%d) for UUID %s keyspace %s and workflow %s on tablet %s

What it means

This error is thrown by the vdiff engine's show-action handler on a vttablet when a query for a vdiff record by UUID returns more than one row. The _vt.vdiff table should hold at most one row per (keyspace, workflow, UUID) triple, so multiple matches indicate corrupt or duplicated vdiff state. The handler aborts rather than guessing which record to summarize.

Source

Thrown at go/vt/vttablet/tabletmanager/vdiff/action.go:352

			return err
		}
		if qr, err = dbClient.ExecuteFetch(query, 1); err != nil {
			return err
		}
		switch len(qr.Rows) {
		case 0:
			return fmt.Errorf("no vdiff found for UUID %s keyspace %s and workflow %s on tablet %s",
				vdiffUUID, req.Keyspace, req.Workflow, topoproto.TabletAliasString(vde.thisTablet.Alias))
		case 1:
			row := qr.Named().Row()
			vdiffID, _ := row["id"].ToInt64()
			summary, err := vde.getVDiffSummary(vdiffID, dbClient, req.GetOptions().GetReportOptions())
			resp.Output = summary
			if err != nil {
				return err
			}
		default:
			return fmt.Errorf("too many vdiffs found (%d) for UUID %s keyspace %s and workflow %s on tablet %s",
				len(qr.Rows), vdiffUUID, req.Keyspace, req.Workflow, topoproto.TabletAliasString(vde.thisTablet.Alias))
		}
	}
	switch req.ActionArg {
	case AllActionArg:
		query, err := sqlparser.ParseAndBind(sqlGetMostRecentVDiffByKeyspaceWorkflow,
			sqltypes.StringBindVariable(req.Keyspace),
			sqltypes.StringBindVariable(req.Workflow),
			sqltypes.StringBindVariable(vde.dbName),
			sqltypes.Int64BindVariable(maxVDiffsToReport),
		)
		if err != nil {
			return err
		}
		if qr, err = dbClient.ExecuteFetch(query, -1); err != nil {
			return err
		}
		resp.Output = sqltypes.ResultToProto3(qr)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Inspect the _vt.vdiff table on the tablet: SELECT * FROM _vt.vdiff WHERE vdiff_uuid='<uuid>' and identify the duplicate rows.
  2. Delete the stale/duplicate rows keeping the correct one (DELETE FROM _vt.vdiff WHERE id=<stale id>).
  3. Re-run the vdiff from scratch: delete all vdiff rows for the workflow and issue a fresh VDiff Create.
  4. If duplication came from a backup restore, pick a healthy tablet/shard and let vtctld vdiff operate against it.

Example fix

// before (mysql on tablet)
SELECT id, vdiff_uuid, workflow FROM _vt.vdiff WHERE vdiff_uuid='6ba7b810-...';
-- returns 2 rows
// after
DELETE FROM _vt.vdiff WHERE id=42; -- keep the correct row
-- then re-run: vtctldclient VDiff --keyspace ks --workflow wf show 6ba7b810-...
Defensive patterns

Strategy: validation

Validate before calling

rows, _ := tabletClient.Query("SELECT COUNT(*) FROM _vt.vdiff WHERE vdiff_uuid='"+uuid+"'")
if rows[0][0].AsInt64() > 1 { // dedupe before issuing show
  cleanupDuplicates(uuid)
}

Type guard

func hasSingleVDiffRow(n int) bool { return n == 1 }

Prevention

When it happens

Trigger: Calling PerformVDiffAction with Action=Show and ActionArg set to a UUID when sqlGetVDiffID (or the UUID lookup query) matches len(qr.Rows) > 1 rows in the _vt.vdiff table on the tablet.

Common situations: Manual inserts into _vt.vdiff during debugging or recovery; orphaned/duplicated rows left by a crashed or interrupted vdiff; running the show against a tablet whose local _vt schema was restored from an inconsistent backup.

Related errors


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