vitessio/vitess · error

err

Error message

err

What it means

Horizon.AddPredicate is pushing a predicate down into the subquery/derived table below the horizon. To do that it must resolve the expression's table info; if the semantic table lookup fails with anything other than the handled ErrNotSingleTable, the planner panics with the raw error. This is an internal-invariant failure: it means the planner was asked to add a predicate it cannot attribute to a known table.

Source

Thrown at go/vt/vtgate/planbuilder/operators/horizon.go:95

// This logic can also be used to check if this is a derived table that can be had on the left hand side of a vtgate join.
// Since vtgate joins are always nested loop joins, we can't execute them on the RHS
// if they do some things, like LIMIT or GROUP BY on wrong columns
func (h *Horizon) IsMergeable(ctx *plancontext.PlanningContext) bool {
	return isMergeable(ctx, h.Query, h)
}

func (h *Horizon) AddPredicate(ctx *plancontext.PlanningContext, expr sqlparser.Expr) Operator {
	if _, isUNion := h.Source.(*Union); isUNion {
		// If we have a derived table on top of a UNION, we can let the UNION do the expression rewriting
		h.Source = h.Source.AddPredicate(ctx, expr)
		return h
	}
	tableInfo, err := ctx.SemTable.TableInfoForExpr(expr)
	if err != nil {
		if errors.Is(err, semantics.ErrNotSingleTable) {
			return newFilter(h, expr)
		}
		panic(err)
	}

	newExpr := semantics.RewriteDerivedTableExpression(expr, tableInfo)
	if ctx.ContainsAggr(newExpr) {
		return newFilter(h, expr)
	}
	h.Source = h.Source.AddPredicate(ctx, newExpr)
	return h
}

func (h *Horizon) AddColumn(ctx *plancontext.PlanningContext, reuse bool, _ bool, expr *sqlparser.AliasedExpr) int {
	if !reuse {
		panic(errNoNewColumns)
	}
	col, ok := expr.Expr.(*sqlparser.ColName)
	if !ok {
		panic(vterrors.VT13001("cannot push non-ColName expression to horizon"))
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Check the inner error message to find which expression/table could not be resolved
  2. Ensure the expression's columns have been rewritten via semantics.RewriteDerivedTableExpression before calling AddPredicate
  3. Verify the predicate passes semantic analysis (tables present in the scope) before routing it to the Horizon
  4. If ErrNotSingleTable is expected in your case, the planner already falls back to a filter — this panic means a different resolution bug; file/inspect a Vitess issue with the query
Defensive patterns

Strategy: try-catch

Validate before calling

// Vitess planner code: before calling AddPredicate, ensure the expr resolves
if _, err := ctx.SemTable.TableInfoForExpr(expr); err != nil && !errors.Is(err, semantics.ErrNotSingleTable) {
    // handle or reject the expression before it reaches Horizon.AddPredicate
}

Try / catch

// Vitess recovers planner panics at the VTGate boundary and converts them to vterrors;
// when extending the planner, wrap experimental calls:
func safeAddPredicate(h *operators.Horizon, ctx *plancontext.PlanningContext, e sqlparser.Expr) (op operators.Operator, err error) {
    defer func() { if r := recover(); r != nil { err = fmt.Errorf("AddPredicate panicked: %v", r) } }()
    return h.AddPredicate(ctx, e), nil
}

Prevention

When it happens

Trigger: Calling AddPredicate on a Horizon with an expression whose tables cannot be resolved by ctx.SemTable.TableInfoForExpr (e.g. an expression referencing an unknown/undone table mapping). ErrNotSingleTable is handled (falls back to newFilter); any other error escapes as this panic.

Common situations: Developing new Vitess planner features or rewriting expressions so they reference tables not registered in the SemTable; bugs in derived-table expression rewriting that leave dangling column references.

Related errors


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