vitessio/vitess · error

VT13001

VT13001

Error message

unexpected statement type %T

What it means

expandHorizon dispatches horizon expansion based on the statement type, supporting only *sqlparser.Select and *sqlparser.Union. Any other sqlparser.TableStatement reaching it panics with VT13001 'unexpected statement type %T' — an unimplemented planning path.

Source

Thrown at go/vt/vtgate/planbuilder/operators/horizon_expanding.go:39

	"fmt"
	"strings"

	"vitess.io/vitess/go/slice"
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vterrors"
	"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
	"vitess.io/vitess/go/vt/vtgate/semantics"
)

func expandHorizon(ctx *plancontext.PlanningContext, horizon *Horizon) (Operator, *ApplyResult) {
	statement := horizon.selectStatement()
	switch sel := statement.(type) {
	case *sqlparser.Select:
		return expandSelectHorizon(ctx, horizon, sel)
	case *sqlparser.Union:
		return expandUnionHorizon(ctx, horizon, sel)
	}
	panic(vterrors.VT13001(fmt.Sprintf("unexpected statement type %T", statement)))
}

func expandUnionHorizon(ctx *plancontext.PlanningContext, horizon *Horizon, union *sqlparser.Union) (Operator, *ApplyResult) {
	op := horizon.Source

	qp := horizon.getQP(ctx)

	if len(qp.OrderExprs) > 0 {
		op = newOrdering(op, qp.OrderExprs)
	}

	if union.Limit != nil {
		op = newLimit(op, union.Limit, false)
	}

	if horizon.TableId != nil {
		proj := newAliasedProjection(op)
		proj.DT = &DerivedTable{

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Identify the %T type printed in the message to see which statement leaked in
  2. Simplify the query (remove/restructure WITH clauses, subquery nesting)
  3. Check Vitess issue tracker / upgrade — VT13001 marks unimplemented functionality; file a bug with the query
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check the statement kind before horizon expansion
switch stmt.(type) {
case *sqlparser.Select, *sqlparser.Union:
    // supported
default:
    // bail out to a generic plan path
}

Type guard

func isExpandableStatement(s sqlparser.TableStatement) bool {
    switch s.(type) {
    case *sqlparser.Select, *sqlparser.Union:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: pushOrExpandHorizon (or mergeCTE) handing expandHorizon a statement type other than Select/Union — e.g. an unexpected AST node produced by an upstream rewrite or a CTE merged into a non-standard statement.

Common situations: Bugs in CTE handling or query rewrites leaking unexpected AST nodes into horizon expansion; effectively never user-caused directly, but triggered by specific query shapes (WITH clauses, unusual nesting).

Related errors


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