vitessio/vitess · error

VT13001

VT13001

Error message

could not find the column '%s' on the UNION

What it means

VT13001 signals an internal planner programming error. While distributing a predicate to each UNION source, the planner looks up the predicate's column name in the offsets map built from the first SELECT's columns; if a source's column cannot be found there, the planner's column-mapping invariant is broken and it panics instead of emitting a wrong plan. The message includes the missing column name.

Source

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

	for i := range u.Sources {
		predicate := expr

		if jp, ok := predicate.(*predicates.JoinPredicate); ok {
			// Create a new JoinPredicate for each source to keep tracking working
			// We can't use `*JoinPredicate.Clone` here as that would update the tracker and overwrite
			// 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 {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify the column named in the panic message ('could not find the column %s on the UNION') actually appears in the first SELECT's output list, and add it if not.
  2. Use explicit, matching column names/aliases in all UNION arms so the predicate column resolves cleanly.
  3. Minimize the query and check against the latest Vitess version; if a valid query triggers this, file a planner bug with the query and stack trace.

Example fix

// before: predicate references a column not in the union output
SELECT id FROM a UNION SELECT x FROM b) WHERE name = 'x'

// after: ensure the column is selected
SELECT id, name FROM a UNION SELECT x, y AS name FROM b) WHERE name = 'x'
Defensive patterns

Strategy: validation

Validate before calling

// ensure every predicate column exists in the union's first SELECT output
want := strings.ToLower(colName)
found := false
for _, se := range unionOp.GetSelectFor(0).GetColumns() {
    if ae, ok := se.(*sqlparser.AliasedExpr); ok && strings.ToLower(ae.ColumnName()) == want {
        found = true
    }
}
if !found {
    return errors.New("predicate column missing from UNION output")
}

Type guard

func columnInUnion(u *operators.Union, col string) bool {
    for _, se := range u.GetSelectFor(0).GetColumns() {
        if ae, ok := se.(*sqlparser.AliasedExpr); ok {
            if strings.ToLower(ae.ColumnName()) == strings.ToLower(col) {
                return true
            }
        }
    }
    return false
}

Try / catch

// Internal invariant panic; pre-validate columns. If a recovery boundary exists:
defer func() {
    if r := recover(); r != nil {
        if vte, ok := r.(error); ok && vterrors.Code(vte) == vtrpcpb.Code_VT13001 {
            // treat as planner bug: log query + stack, re-panic or return internal error
        }
    }
}()

Prevention

When it happens

Trigger: During Union.AddPredicate / predicatePerSource, a ColName in the pushed expression is not present (case-insensitively) in the offsets map built from the first SELECT's column list — e.g. the predicate references a column that the UNION does not actually output, or a column-name mismatch between UNION arms.

Common situations: Queries whose WHERE clause on a UNION references a column missing from the first SELECT, or planner regressions where offsets were built before query normalization/aliasing (e.g. unmatched case or renamed output columns).

Related errors


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