vitessio/vitess · error
--force-cut-over-after is only valid in 'vitess' strategy. F
Error message
--force-cut-over-after is only valid in 'vitess' strategy. Found %v value in '%v' strategy
What it means
ParseDDLStrategy rejects the --force-cut-over-after parameter when the selected strategy is not 'vitess' (or 'online', an alias). That cutover-control parameter is only meaningful for vitess-managed online DDL, so any nonzero value with mysql/direct strategies errors.
Source
Thrown at go/vt/schema/ddl_strategy.go:148
}
if _, err := setting.CutOverThreshold(); err != nil {
return nil, err
}
if _, err := setting.RetainArtifactsDuration(); err != nil {
return nil, err
}
if _, err := setting.SessionVariables(); err != nil {
return nil, err
}
cutoverAfter, err := setting.ForceCutOverAfter()
if err != nil {
return nil, err
}
switch setting.Strategy {
case DDLStrategyVitess, DDLStrategyOnline:
default:
if cutoverAfter != 0 {
return nil, fmt.Errorf("--force-cut-over-after is only valid in 'vitess' strategy. Found %v value in '%v' strategy", cutoverAfter, setting.Strategy)
}
}
switch setting.Strategy {
case DDLStrategyVitess, DDLStrategyOnline, DDLStrategyMySQL, DDLStrategyDirect:
if opts := setting.RuntimeOptions(); len(opts) > 0 {
return nil, fmt.Errorf("invalid flags for %v strategy: %s", setting.Strategy, strings.Join(opts, " "))
}
}
return setting, nil
}
// isFlag return true when the given string is a CLI flag of the given name
func isFlag(s string, name string) bool {
if s == "-"+name {
return true
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Remove --force-cut-over-after from the ddl_strategy value, e.g. SET @@ddl_strategy='mysql'.
- Switch to strategy 'vitess' or 'online' if you actually want controlled cutover with --force-cut-over-after.
- Fix automation that injects vitess-specific flags into non-vitess strategies.
- Use valid syntax SET @@ddl_strategy='vitess --force-cut-over-after=24h' when intended.
Example fix
// before SET @@ddl_strategy='mysql --force-cut-over-after=24h'; // after SET @@ddl_strategy='vitess --force-cut-over-after=24h'; // or drop the flag
Defensive patterns
Strategy: validation
Validate before calling
s := schema.ParseDDLStrategy(strategyName)
if (strategy == "mysql" || strategy == "direct") && strings.Contains(strategyName, "--force-cut-over-after") {
return errors.New("--force-cut-over-after requires vitess/online strategy")
} Type guard
func cutoverAllowed(s *schema.DDLStrategySetting) bool {
return s.Strategy == schema.DDLStrategyVitess || s.Strategy == schema.DDLStrategyOnline
} Try / catch
setting, err := schema.ParseDDLStrategy(v)
if err != nil { return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "ddl_strategy invalid: %v", err) } Prevention
- Only append --force-cut-over-after to vitess/online strategies
- Keep DDL strategy templates per-strategy, not shared
When it happens
Trigger: SET @@ddl_strategy='mysql --force-cut-over-after=24h' or 'direct --force-cut-over-after=...' — a nonzero cutoverAfter parsed while setting.Strategy is mysql or direct.
Common situations: Copy-pasting a vitess strategy string and editing only the strategy token, forgetting to remove parameters; automation templates appending --force-cut-over-after to every strategy; misunderstanding that mysql/direct run native DDL so forced cutover is meaningless.
Related errors
- invalid flags for %v strategy: %s
- Unknown online DDL strategy: '%v'
- session variable %q is not allowed
- duplicate session variable name: %q
- found no possible unique key on `%s`
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/9330971474d7b36c.
Report an issue: GitHub.