vitessio/vitess · error

no completed or stopped vdiff found for UUID %s on tablet %s

Error message

no completed or stopped vdiff found for UUID %s on tablet %s

What it means

When resuming, Vitess first tries to resume a completed/stopped vdiff; if no rows are affected it attempts to start (resume a never-started) vdiff, and if that also affects 0 rows, neither a completed/stopped nor an unstarted record matches the UUID, so it errors. The UUID exists conceptually but is not in a resumable state on this tablet.

Source

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

			if err != nil {
				return 0, err
			}
			if qr, err = dbClient.ExecuteFetch(query, 1); err != nil {
				return 0, err
			}
			return qr.RowsAffected, nil
		}
		rowsAffected, err := execResume(sqlResumeVDiff)
		if err != nil {
			return err
		}
		if rowsAffected == 0 { // See if it's a vdiff that was never started
			rowsAffected, err := execResume(sqlStartVDiff)
			if err != nil {
				return err
			}
			if rowsAffected == 0 {
				return fmt.Errorf("no completed or stopped vdiff found for UUID %s on tablet %s",
					req.VdiffUuid, topoproto.TabletAliasString(vde.thisTablet.Alias))
			}
		}
	}

	resp.VdiffUuid = req.VdiffUuid
	qr, err = vde.getVDiffByID(ctx, dbClient, resp.Id)
	if err != nil {
		return err
	}
	vdiffRecord := qr.Named().Row()
	if vdiffRecord == nil {
		return fmt.Errorf("unable to %s vdiff for UUID %s as it was not found on tablet %v (%w)",
			action, req.VdiffUuid, topoproto.TabletAliasString(vde.thisTablet.Alias), err)
	}
	if action == ResumeAction {
		// Use the existing options from the vdiff record.
		options = optionsZeroVal

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Run vdiff show to check the current state of the UUID on this tablet
  2. If it's already running, wait or stop it instead of resuming
  3. If it's in a bad state, delete it and create a fresh vdiff
  4. Ensure you're targeting the tablet that actually holds the record

Example fix

// before
vtctldclient VDiff resume --uuid xyz  // state=running
// after
vtctldclient VDiff show --uuid xyz    // inspect state
vtctldclient VDiff delete --uuid xyz
vtctldclient VDiff create && vtctldclient VDiff resume
Defensive patterns

Strategy: validation

Validate before calling

qr, _ := dbClient.ExecuteFetch("SELECT state FROM _vt.vdiff_tablet WHERE uuid=?", 1, true)
if len(qr.Rows) == 0 { return errors.New("no such vdiff") }
state, _ := qr.Named().Row()["state"].ToString()
if state != "completed" && state != "stopped" { return fmt.Errorf("non-resumable state: %s", state) }

Try / catch

if strings.Contains(err.Error(), "no completed or stopped vdiff found") {
    // inspect state; delete and re-create if unrecoverable
}

Prevention

When it happens

Trigger: vdiff resume where the UUID's row is in a non-resumable state (already running/errored/cancelled) or missing on the tablet — both UPDATEs (resume and start) matched 0 rows in handleCreateResumeAction.

Common situations: Resuming a vdiff that is currently running; resuming one that was cancelled or completed and cleaned; using a UUID that was never created on this specific tablet; repeated resume after the record transitioned states.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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