vitessio/vitess · error

VT09015

VT09015

Error message

schema tracking required

What it means

VT09015 ('schema tracking required') is raised in Union.predicatePerSource while rewriting a pushed-down predicate for each UNION source. The column offsets map (built from the first SELECT's columns) located a position, but the corresponding select item in that source's SELECT is not a plain *sqlparser.AliasedExpr (e.g. it is a star expansion or other non-aliased item), so the underlying expression cannot be substituted. Vitess panics because this state indicates the query planning phase needed schema/semantic tracking that was not available for this shape of query.

Source

Thrown at go/vt/vtgate/planbuilder/operators/union.go:143

			// the expression for the original predicate
			predicate = ctx.PredTracker.NewJoinPredicate(jp.Current())
		}

		predicate = sqlparser.CopyOnRewrite(predicate, nil, func(cursor *sqlparser.CopyOnWriteCursor) {
			col, ok := cursor.Node().(*sqlparser.ColName)
			if !ok {
				return
			}

			idx, ok := offsets[col.Name.Lowered()]
			if !ok {
				panic(vterrors.VT13001(fmt.Sprintf("could not find the column '%s' on the UNION", sqlparser.String(col))))
			}

			sel := u.GetSelectFor(i)
			ae, ok := sel.GetColumns()[idx].(*sqlparser.AliasedExpr)
			if !ok {
				panic(vterrors.VT09015())
			}

			cursor.Replace(ae.Expr)
		}, nil).(sqlparser.Expr)

		exprPerSource[i] = predicate
	}

	return exprPerSource
}

func (u *Union) GetSelectFor(source int) *sqlparser.Select {
	src := u.Sources[source]
	for {
		switch op := src.(type) {
		case *Horizon:
			return getFirstSelect(op.Query)
		case *Route:

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Rewrite the query to use explicit column lists instead of `*` in the UNION branches (e.g. `SELECT a, b FROM t1 UNION SELECT c, d FROM t2`).
  2. Simplify the predicate so it references columns that map to plain aliased expressions in all UNION branches.
  3. If this is hit from valid SQL, file a Vitess issue: it indicates an unsupported plan shape that should be caught earlier with a clearer error.

Example fix

// before: predicate references a UNION column produced by SELECT *
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY k;
// after
SELECT k, v FROM t1 UNION SELECT k2, v2 FROM t2 ORDER BY k;
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Calling Union.AddPredicate (which calls predicatePerSource) when a UNION source's first SELECT at the matched column index contains an item that is not *sqlparser.AliasedExpr — e.g. a `SELECT *` that survived planning, or a NEXT-value expression, at the offset the predicate column resolves to.

Common situations: Queries with UNION whose sources use `*` (star) select lists combined with a WHERE/GROUP BY/HAVING predicate pushed onto the UNION; typically hit during Vitess development or when testing unhandled query shapes, not by end-user misconfiguration.

Related errors


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