{"record":{"id":"1237f48afbc7f9f2","repo":"vitessio/vitess","slug":"err-1237f4","errorCode":null,"errorMessage":"err","messagePattern":"err","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/planbuilder/operators/horizon.go","lineNumber":95,"sourceCode":"// 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.\n// Since vtgate joins are always nested loop joins, we can't execute them on the RHS\n// if they do some things, like LIMIT or GROUP BY on wrong columns\nfunc (h *Horizon) IsMergeable(ctx *plancontext.PlanningContext) bool {\n\treturn isMergeable(ctx, h.Query, h)\n}\n\nfunc (h *Horizon) AddPredicate(ctx *plancontext.PlanningContext, expr sqlparser.Expr) Operator {\n\tif _, isUNion := h.Source.(*Union); isUNion {\n\t\t// If we have a derived table on top of a UNION, we can let the UNION do the expression rewriting\n\t\th.Source = h.Source.AddPredicate(ctx, expr)\n\t\treturn h\n\t}\n\ttableInfo, err := ctx.SemTable.TableInfoForExpr(expr)\n\tif err != nil {\n\t\tif errors.Is(err, semantics.ErrNotSingleTable) {\n\t\t\treturn newFilter(h, expr)\n\t\t}\n\t\tpanic(err)\n\t}\n\n\tnewExpr := semantics.RewriteDerivedTableExpression(expr, tableInfo)\n\tif ctx.ContainsAggr(newExpr) {\n\t\treturn newFilter(h, expr)\n\t}\n\th.Source = h.Source.AddPredicate(ctx, newExpr)\n\treturn h\n}\n\nfunc (h *Horizon) AddColumn(ctx *plancontext.PlanningContext, reuse bool, _ bool, expr *sqlparser.AliasedExpr) int {\n\tif !reuse {\n\t\tpanic(errNoNewColumns)\n\t}\n\tcol, ok := expr.Expr.(*sqlparser.ColName)\n\tif !ok {\n\t\tpanic(vterrors.VT13001(\"cannot push non-ColName expression to horizon\"))\n\t}","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/planbuilder/operators/horizon.go#L77-L113","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the inner error message to find which expression/table could not be resolved","Ensure the expression's columns have been rewritten via semantics.RewriteDerivedTableExpression before calling AddPredicate","Verify the predicate passes semantic analysis (tables present in the scope) before routing it to the Horizon","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Vitess planner code: before calling AddPredicate, ensure the expr resolves\nif _, err := ctx.SemTable.TableInfoForExpr(expr); err != nil && !errors.Is(err, semantics.ErrNotSingleTable) {\n    // handle or reject the expression before it reaches Horizon.AddPredicate\n}","typeGuard":null,"tryCatchPattern":"// Vitess recovers planner panics at the VTGate boundary and converts them to vterrors;\n// when extending the planner, wrap experimental calls:\nfunc safeAddPredicate(h *operators.Horizon, ctx *plancontext.PlanningContext, e sqlparser.Expr) (op operators.Operator, err error) {\n    defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"AddPredicate panicked: %v\", r) } }()\n    return h.AddPredicate(ctx, e), nil\n}","preventionTips":["Only route predicates that passed semantic analysis to Horizon.AddPredicate","Treat ErrNotSingleTable explicitly (multi-table predicates go to filters, not the horizon)","Add unit tests for predicates over derived tables before planner changes"],"tags":["planner","internal-invariant","panic","vtgate"],"backgroundTag":"unresolved-table-expression","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}