vitessio/vitess · error
switch should be exhaustive
Error message
switch should be exhaustive
What it means
visitAllSelects() walks a SelectStatement tree recursively and panics when it encounters a SelectStatement implementation not covered by its type switch. The switch is expected to handle every SelectStatement variant in the AST; an unhandled one means a new/unknown node type reached the visitor.
Source
Thrown at go/vt/sqlparser/ast_funcs.go:2948
type visitor struct {
idx int
}
func (v *visitor) visitAllSelects(in TableStatement, f func(p *Select, idx int) error) error {
switch sel := in.(type) {
case *Select:
err := f(sel, v.idx)
v.idx++
return err
case *Union:
err := v.visitAllSelects(sel.Left, f)
if err != nil {
return err
}
return v.visitAllSelects(sel.Right, f)
}
panic("switch should be exhaustive")
}
// IsRestrict returns true if the reference action is of restrict type.
func (ra ReferenceAction) IsRestrict() bool {
switch ra {
case Restrict, NoAction, DefaultAction:
return true
default:
return false
}
}
// IsCascade returns true if the reference action is of cascade type.
func (ra ReferenceAction) IsCascade() bool {
switch ra {
case Cascade:
return true
default:View on GitHub (pinned to 01a25a7d17)
Solutions
- Regenerate the sqlparser code with `make codegen` so the visitor covers all current SelectStatement variants
- Update your Vitess version so the visitor and AST node types are from the same release
- Find the custom/unknown node type in your AST tree and replace it with a supported SelectStatement
- Extend visitAllSelects' switch to handle the missing variant and file/fix the upstream gap
Example fix
// before
switch sel := sel.(type) {
case *sqlparser.Select: ...
case *sqlparser.Union: ...
} // falls through to panic on new node type
// after
// regenerate: make codegen
// or add the variant:
case *sqlparser.NewSelectVariant: ...
_ = sel Defensive patterns
Strategy: validation
Validate before calling
func isKnownSelect(sel sqlparser.SelectStatement) bool {
switch sel.(type) {
case *sqlparser.Select, *sqlparser.Union:
return true
default:
return false
}
} Type guard
func isSupportedSelect(sel sqlparser.SelectStatement) bool {
switch sel.(type) {
case *sqlparser.Select:
return true
case *sqlparser.Union:
return true
default:
return false
}
} Try / catch
func visitSelectsSafe(sel sqlparser.SelectStatement, f func(sqlparser.Select) error) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("visitor panicked: %v", r)
}
}()
return visitAllSelects(sel, f)
} Prevention
- Keep sqlparser generated files in sync via `make codegen`
- Upgrade parser and AST together — never mix versions
- Add a default-case test for your visitor over all AST node kinds
- Reject unknown SelectStatement types at input boundaries
When it happens
Trigger: Calling code that invokes the visitor path over a SelectStatement whose concrete type is not *Select, *Union, *SetOp, or whatever variants the switch handles — typically a newly added AST node type or a custom node injected into the tree.
Common situations: Running on a Vitess version where a new SelectStatement type was introduced but this internal visitor was not regenerated/updated; custom AST extensions in forks; stale generated code after a parser change without `make codegen`.
Related errors
- invalid IntervalDateExpr syntax
- IntervalDateExpr.Unit is not set
- no columns available
- unexpected TrackedBuffer type %T
- unexepcted TrackedBuffer type %T
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/10fcd2f404ce3e5b.
Report an issue: GitHub.