vitessio/vitess · error
err
Error message
err
What it means
This is an unrecoverable panic raised inside the VTGate planning stage while adding columns to an Aggregator operator. `expr.GetAliasedExpr()` fails when a select expression is not a plain aliased expression at this point of horizon expansion, indicating an internal planner invariant violation rather than an invalid user query. The original error is re-panicked so planning aborts instead of producing a wrong plan.
Source
Thrown at go/vt/vtgate/planbuilder/operators/horizon_expanding.go:272
newExprs = append(newExprs, newExpr)
aggr.SubQueryExpression = append(aggr.SubQueryExpression, subqs...)
} else {
newExprs = append(newExprs, expr)
}
}
if len(aggr.SubQueryExpression) > 0 {
aggr.setPushColumn(newExprs)
}
return aggr
}
func addAllColumnsToAggregator(ctx *plancontext.PlanningContext, a *Aggregator, qp *QueryProjection) {
outer:
for colIdx, expr := range qp.SelectExprs {
ae, err := expr.GetAliasedExpr()
if err != nil {
panic(err)
}
addedToCol := false
for idx, groupBy := range a.Grouping {
if ctx.SemTable.EqualsExprWithDeps(groupBy.Inner, ae.Expr) {
if !addedToCol {
a.Columns = append(a.Columns, ae)
addedToCol = true
}
if groupBy.ColOffset < 0 {
a.Grouping[idx].ColOffset = colIdx
}
}
}
if addedToCol {
continue
}
for idx, aggr := range a.Aggregations {
if ctx.SemTable.EqualsExprWithDeps(aggr.Original.Expr, ae.Expr) && aggr.ColOffset < 0 {View on GitHub (pinned to 01a25a7d17)
Solutions
- Capture the failing query and file a bug with the Vitess project — this panic indicates a planner bug, not user error
- Simplify the query: rewrite complex SELECT expressions so each is a plain column reference or explicitly aliased expression
- Try restructuring the aggregation (e.g. move expressions into a derived table and aggregate over it)
- Check the Vitess version and upgrade — such invariant panics are frequently fixed in newer releases
Example fix
// before (query that may trigger) SELECT a+b, COUNT(*) FROM t GROUP BY a+b; // after (pre-alias so planner sees a plain aliased expr) SELECT (a+b) AS s, COUNT(*) FROM t GROUP BY s;
Defensive patterns
Strategy: validation
Validate before calling
// Run the query with ONLY_FULL_GROUP_BY against a plain MySQL first;
// only plain aliased expressions in the SELECT list of aggregated queries.
func hasPlainAliasedSelectExprs(sel *sqlparser.Select) bool {
for _, e := range sel.SelectExprs {
if _, ok := e.(*sqlparser.AliasedExpr); !ok { return false }
}
return true
} Type guard
if ae, ok := expr.(sqlparser.SelectExpr); ok {
if _, isAliased := ae.GetAliasedExpr(); isAliased == false { /* avoid path */ }
} Try / catch
// In Vitess code paths that call planning, recover planner panics:
func safePlan(q string) (plan any, err error) {
defer func() {
if r := recover(); r != nil { err = fmt.Errorf("planning failed: %v", r) }
}()
return planQuery(q)
} Prevention
- Keep SELECT expressions explicitly aliased in GROUP BY queries
- Test aggregation queries against a real MySQL with ONLY_FULL_GROUP_BY before Vitess
- Pin a known-good Vitess version and read release notes for planner fixes
- Report panics with full query + version to Vitess rather than working around silently
When it happens
Trigger: A query containing an aggregation reaches addAllColumnsToAggregator (via createProjectionWithAggr) and one of the QueryProjection SelectExprs cannot be converted to an *sqlparser.AliasedExpr by GetAliasedExpr() — e.g. an unexpected expression shape survives earlier planning phases.
Common situations: Complex or unusual SELECT expressions combined with GROUP BY that the planner's earlier rewrite stages did not normalize; often hit during development of new SQL features or by fuzzer-generated queries rather than ordinary application SQL.
Related errors
- panic: %v
- SetIdleTimeout called when timer not initialized
- negative capacity
- timestampBusy when borrowing a time
- err
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/8808dee2b73b1224.
Report an issue: GitHub.