vitessio/vitess · error · VitessError
VT13001
VT13001
Error message
VT13001: [BUG] unhandled default case
What it means
VT13001 internal-bug panic in Phase.String(). The method enumerates all known planning phases; a Phase value outside the enumerated cases (uninitialized or future/foreign value) hits the default and panics. It exists purely to catch programming errors when a new phase is added without updating String.
Source
Thrown at go/vt/vtgate/planbuilder/operators/phases.go:68
return "physicalTransform"
case initialPlanning:
return "initial horizon planning optimization"
case pullDistinctFromUnion:
return "pull distinct from UNION"
case delegateAggregation:
return "split aggregation between vtgate and mysql"
case recursiveCTEHorizons:
return "expand recursive CTE horizons"
case addAggrOrdering:
return "optimize aggregations with ORDER BY"
case cleanOutPerfDistinct:
return "optimize Distinct operations"
case subquerySettling:
return "settle subqueries"
case dmlWithInput:
return "expand update/delete to dml with input"
default:
panic(vterrors.VT13001("unhandled default case"))
}
}
func (p Phase) shouldRun(s semantics.QuerySignature) bool {
switch p {
case pullDistinctFromUnion:
return s.Union
case delegateAggregation:
return s.Aggregation
case recursiveCTEHorizons:
return s.RecursiveCTE
case addAggrOrdering:
return s.Aggregation
case cleanOutPerfDistinct:
return s.Distinct
case subquerySettling:
return s.SubQueries
case dmlWithInput:View on GitHub (pinned to 01a25a7d17)
Solutions
- Add the missing Phase case to the String() switch in go/vt/vtgate/planbuilder/operators/phases.go
- File a bug with the stack trace if this appears without local code changes
- Run on the latest release where all phases are covered
Example fix
// before
case dmlWithInput:
return "expand update/delete to dml with input"
default:
panic(vterrors.VT13001("unhandled default case"))
// after: add the new phase before default
case myNewPhase:
return "my new phase"
default:
panic(vterrors.VT13001("unhandled default case")) Defensive patterns
Strategy: type-guard
Validate before calling
// Vitess contributors: ensure every Phase constant has a String case
for (const p of allPhases) {
if (phaseToString(p) === undefined) throw new Error('missing String case for phase ' + p);
} Type guard
null
Try / catch
null
Prevention
- When adding a Phase constant, update String() and shouldRun() in the same change
- Enable exhaustive-switch linters
- Only maintainers/developers normally encounter this
When it happens
Trigger: Calling String() (e.g. via logging/tracing a phase) on a Phase value not covered by the switch — typically a newly added phase constant whose String case was forgotten, or a zero-value/uninitialized Phase.
Common situations: Development of Vitess itself (adding a phase to phases.go without updating String); end users only see it via a planner bug's stack trace in logs.
Related errors
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/98d9fd78011438e6.
Report an issue: GitHub.