vitessio/vitess · warning
VT12001
VT12001
Error message
pushing predicates on UNION where the first SELECT contains * or NEXT
What it means
VT12001 is an unsupported-feature error raised when the planner attempts to push a predicate onto a UNION whose first SELECT contains a star (*) expression or a NEXT-sequence expression. Pushing predicates to each UNION source requires mapping the predicate's column to positional offsets in the first SELECT's column list, which is impossible when the first SELECT expands `*` or uses NEXT, so the planner fails fast instead of producing an incorrect plan.
Source
Thrown at go/vt/vtgate/planbuilder/operators/union.go:103
to end up with an operator tree that looks something like this:
select * (
select foo as col, bar from tbl1 where foo = 42
union
select id, baz from tbl2 where id = 42
) as X
Notice how `X.col = 42` has been translated to `foo = 42` and `id = 42` on respective WHERE clause.
The first SELECT of the union dictates the column names, and the second is whatever expression
can be found on the same offset. The names of the RHS are discarded.
*/
func (u *Union) AddPredicate(ctx *plancontext.PlanningContext, expr sqlparser.Expr) Operator {
offsets := make(map[string]int)
sel := u.GetSelectFor(0)
for i, selectExpr := range sel.GetColumns() {
ae, ok := selectExpr.(*sqlparser.AliasedExpr)
if !ok {
panic(vterrors.VT12001("pushing predicates on UNION where the first SELECT contains * or NEXT"))
}
offsets[strings.ToLower(ae.ColumnName())] = i
}
exprPerSource := u.predicatePerSource(ctx, expr, offsets)
for i, src := range u.Sources {
u.Sources[i] = src.AddPredicate(ctx, exprPerSource[i])
}
return u
}
func (u *Union) predicatePerSource(ctx *plancontext.PlanningContext, expr sqlparser.Expr, offsets map[string]int) []sqlparser.Expr {
exprPerSource := make([]sqlparser.Expr, len(u.Sources))
for i := range u.Sources {
predicate := expr
View on GitHub (pinned to 01a25a7d17)
Solutions
- Replace `SELECT *` in the first SELECT of the UNION with an explicit column list so the planner can match predicate columns to offsets.
- Remove NEXT VALUE FOR expressions from the first SELECT of the UNION, or compute them outside the union.
- Restructure the query: wrap the UNION in a derived table with explicit column names and apply the WHERE clause outside it.
- If the query must keep `*`, disable the failing pushdown path via planner flags/version-appropriate settings and report the query as an unsupported-shape bug.
Example fix
// before SELECT * FROM a UNION SELECT x, y FROM b WHERE id = 1 // after SELECT id, name FROM a UNION SELECT x, y FROM b WHERE id = 1
Defensive patterns
Strategy: validation
Validate before calling
firstSel := unionOp.GetSelectFor(0)
for _, se := range firstSel.GetColumns() {
if _, ok := se.(*sqlparser.AliasedExpr); !ok {
// first SELECT has * or NEXT; don't attempt predicate pushdown
return
}
} Type guard
func isPushable(union *operators.Union) bool {
for _, se := range union.GetSelectFor(0).GetColumns() {
if _, ok := se.(*sqlparser.AliasedExpr); !ok {
return false
}
}
return true
} Try / catch
// Unsupported-feature panics should be pre-checked; if wrapping a recover boundary:
defer func() {
if r := recover(); r != nil {
if vte, ok := r.(error); ok && vterrors.Code(vte) == vtrpcpb.Code_VT12001 {
// fall back to non-pushdown planning for this union
}
}
}() Prevention
- Always write explicit column lists in the first SELECT of a UNION used with WHERE clauses in Vitess.
- Avoid NEXT VALUE FOR expressions in the first UNION arm when predicates are applied to the union.
- Prefer applying filters to the derived table wrapping a UNION rather than relying on pushdown into it.
When it happens
Trigger: A WHERE/HAVING/join predicate is pushed into a UNION operator while sel.GetColumns()[0..n] of the first SELECT contains anything other than *sqlparser.AliasedExpr — specifically `SELECT *` (or table.*) or `NEXT VALUE FOR seq` in the first arm of the UNION.
Common situations: Users writing `SELECT * FROM a UNION SELECT ...` with a WHERE clause on the union in a sharded Vitess deployment; often surfaces after upgrading planner versions where predicate pushdown into UNIONs became more aggressive.
Related errors
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/41385c53ed74aebb.
Report an issue: GitHub.