vitessio/vitess · error

invalid action '%s'; %s

Error message

invalid action '%s'; %s

What it means

After parsing, VDiff2 converts the second CLI token to a vdiff.VDiffAction. If the token is empty or unrecognized, or the arg count doesn't match any accepted shape, the command returns 'invalid action ...' plus the usage text. This guards against typos and unsupported actions.

Source

Thrown at go/vt/vtctl/vdiff2.go:97

	var actionArg string

	usage := fmt.Errorf("usage: VDiff -- <keyspace>.<workflow> %s [%s|<UUID>]", strings.Join(*(*[]string)(unsafe.Pointer(&vdiff.Actions)), "|"), strings.Join(vdiff.ActionArgs, "|"))
	switch subFlags.NArg() {
	case 1: // for backward compatibility with vdiff1
		action = vdiff.CreateAction
	case 2:
		action = vdiff.VDiffAction(strings.ToLower(subFlags.Arg(1)))
		if action != vdiff.CreateAction {
			return usage
		}
	case 3:
		action = vdiff.VDiffAction(strings.ToLower(subFlags.Arg(1)))
		actionArg = strings.ToLower(subFlags.Arg(2))
	default:
		return usage
	}
	if action == "" {
		return fmt.Errorf("invalid action '%s'; %s", subFlags.Arg(1), usage)
	}
	keyspace, workflowName, err := splitKeyspaceWorkflow(subFlags.Arg(0))
	if err != nil {
		return err
	}

	if *maxRows <= 0 {
		return fmt.Errorf("invalid --limit value (%d), maximum number of rows to compare needs to be greater than 0", *maxRows)
	}

	options := &tabletmanagerdatapb.VDiffOptions{
		PickerOptions: &tabletmanagerdatapb.VDiffPickerOptions{
			TabletTypes: *tabletTypes,
			SourceCell:  *sourceCell,
			TargetCell:  *targetCell,
		},
		CoreOptions: &tabletmanagerdatapb.VDiffCoreOptions{
			Tables:                *tables,

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Run the command with a clearly invalid extra token to print usage, or read the usage string listing valid actions joined with '|'.
  2. Fix the action spelling (case-insensitive; it is lowercased before the check).
  3. If the action exists in a newer Vitess release, upgrade the vtctl binary or use the actions supported by your version.
  4. Put the qualifier (all|last|UUID) in the third position: `VDiff ks.wf show all`.

Example fix

// before
VDiff -- commerce.sell delet 1234   # typo
// after
VDiff -- commerce.sell delete 1234
Defensive patterns

Strategy: validation

Validate before calling

actions := map[vdiff.VDiffAction]bool{"create":true,"show":true,"complete":true,"abort":true,"remove":true}
a := vdiff.VDiffAction(strings.ToLower(actionToken))
if !actions[a] { return fmt.Errorf("unsupported VDiff action %q", actionToken) }

Type guard

func isVDiffAction(s string) bool {
    switch vdiff.VDiffAction(strings.ToLower(s)) {
    case vdiff.CreateAction, vdiff.ShowAction, vdiff.CompleteAction, vdiff.AbortAction:
        return true
    }
    return false
}

Try / catch

if err := runVDiff(args); err != nil {
    if strings.Contains(err.Error(), "invalid action") {
        log.Warn("typo in VDiff action; see usage in error message")
    }
}

Prevention

When it happens

Trigger: `VDiff -- ks.wf <bogus>` where the second argument lowercased is not one of the defined actions (create, show, complete, abort, remove, etc.), or NArg() is 1 with an empty action and the caller intended a real action.

Common situations: Typo'd action names (`vdif` instead of `vdiff` verbs like `stopwatches`); using an action from a newer Vitess version on an older binary; passing an action arg in the action slot (e.g. `VDiff ks.wf all` instead of `VDiff ks.wf show all`).

Understand the failure class

Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.

Related errors


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