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

  1. Regenerate the sqlparser code with `make codegen` so the visitor covers all current SelectStatement variants
  2. Update your Vitess version so the visitor and AST node types are from the same release
  3. Find the custom/unknown node type in your AST tree and replace it with a supported SelectStatement
  4. 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

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


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