vitessio/vitess · error
usage: VDiff -- <keyspace>.<workflow> %s [%s|<UUID>]
Error message
usage: VDiff -- <keyspace>.<workflow> %s [%s|<UUID>]
What it means
commandVDiff2 parses the VDiff command line and constructs a usage error listing all valid actions and action args. It is returned whenever the argument count after `<keyspace>.<workflow>` is not 1 (legacy vdiff1 form), 2, or 3 — i.e. the VDiff subcommand invocation doesn't match any accepted shape.
Source
Thrown at go/vt/vtctl/vdiff2.go:81
maxExtraRowsToCompare := subFlags.Int64("max_extra_rows_to_compare", 1000, "If there are collation differences between the source and target, you can have rows that are identical but simply returned in a different order from MySQL. We will do a second pass to compare the rows for any actual differences in this case and this flag allows you to control the resources used for this operation.")
autoRetry := subFlags.Bool("auto-retry", true, "Should this vdiff automatically retry and continue in case of recoverable errors")
checksum := subFlags.Bool("checksum", false, "Use row-level checksums to compare, not yet implemented")
samplePct := subFlags.Int64("sample_pct", 100, "How many rows to sample, not yet implemented")
verbose := subFlags.Bool("verbose", false, "Show verbose vdiff output in summaries")
wait := subFlags.Bool("wait", false, "When creating or resuming a vdiff, wait for it to finish before exiting")
waitUpdateInterval := subFlags.Duration("wait-update-interval", time.Duration(1*time.Minute), "When waiting on a vdiff to finish, check and display the current status this often")
updateTableStats := subFlags.Bool("update-table-stats", false, "Update the table statistics, using ANALYZE TABLE, on each table involved in the VDiff during initialization. This will ensure that progress estimates are as accurate as possible -- but it does involve locks and can potentially impact query processing on the target keyspace.")
if err := subFlags.Parse(args); err != nil {
return err
}
format = strings.ToLower(format)
var action vdiff.VDiffAction
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))View on GitHub (pinned to 01a25a7d17)
Solutions
- Use `vtctl VDiff -- <keyspace>.<workflow> <action> [<actionArg>|<UUID>]` — 1, 2, or 3 args only after the workflow.
- Check the exact action list: create, show, complete, abort, remove, restart, split, delete, etc. (joined with '|' in the usage message).
- Ensure `--` separates vtctl-level flags from VDiff args so subFlags receives the intended tokens.
- For vdiff1-style invocation, a single extra arg is still accepted (treated as create) — remove extra tokens rather than reformulating.
Example fix
// before VDiff -- commerce.sell show all status // after VDiff -- commerce.sell show all
Defensive patterns
Strategy: validation
Validate before calling
validActions := []string{"create","show","complete","abort","remove","restart","split","delete"}
if len(args) > 3 || (len(args) >= 1 && !slices.Contains(validActions, strings.ToLower(args[0]))) {
return fmt.Errorf("invalid VDiff invocation; usage: VDiff -- <keyspace>.<workflow> <action> [<actionArg>|<UUID>]")
} Try / catch
if err := runVDiff(args); err != nil {
if strings.Contains(err.Error(), "usage: VDiff") {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
} Prevention
- Always separate vtctl flags from VDiff args with `--`.
- Keep the arg count to workflow + action + optional qualifier.
- Check the action list for your exact Vitess version before scripting.
When it happens
Trigger: Calling `vtctl VDiff -- <keyspace>.<workflow>` with zero extra args, or more than 2 args after the workflow (e.g. an extra stray token), so the switch on subFlags.NArg() falls to default and returns the usage error.
Common situations: Copy-pasting vdiff1 syntax; forgetting that the action name is a separate argument (`VDiff ks.wf show` not `VDiff ks.wf show all extra`); shell splitting inserting unexpected tokens; missing the `--` separator so vtctl flags consume arguments.
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
- invalid action '%s'; %s
- invalid --limit value (%d), maximum number of rows to compar
- %v, please provide a valid UUID
- VDiff not implemented in vtcombo
- the <tablet alias> argument is required for the SetReadWrite
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/dbc1c22721e02998.
Report an issue: GitHub.