vitessio/vitess · error
should override
Error message
should override
What it means
CallExpr is an abstract base expression in the evalengine; its eval method is a placeholder that must be overridden by concrete call types (e.g., function calls, stored-procedure-ish nodes). Panicking here means a CallExpr instance that was not subclassed/rewritten into a concrete callable reached the evaluation stage. It signals the expression tree was built or dispatched incorrectly rather than a user-data problem.
Source
Thrown at go/vt/vtgate/evalengine/expr_call.go:32
limitations under the License.
*/
package evalengine
type (
callable interface {
IR
callable() []IR
}
CallExpr struct {
Arguments TupleExpr
Method string
}
)
func (c *CallExpr) eval(*ExpressionEnv) (eval, error) {
panic("should override")
}
func (c *CallExpr) compile(*compiler) (ctype, error) {
panic("should override")
}
func (c *CallExpr) callable() []IR {
return c.Arguments
}
func (c *CallExpr) args(env *ExpressionEnv) ([]eval, error) {
args := make([]eval, 0, len(c.Arguments))
for _, arg := range c.Arguments {
e, err := arg.eval(env)
if err != nil {
return nil, err
}
args = append(args, e)View on GitHub (pinned to 01a25a7d17)
Solutions
- Inspect the query/plan to see which function produced a bare CallExpr and ensure it maps to a concrete evalengine call type
- Add the missing mapping/rewrite so the CallExpr is replaced before evaluation
- If constructing expressions in tests, instantiate a concrete subclass instead of CallExpr
- Report to Vitess maintainers with the query and plan if no local extension exists
Example fix
// before
call := &evalengine.CallExpr{Method: "my_fn"}
v, err := call.eval(env)
// after
call := evalengine.newBuiltinFunc("my_fn", args) // concrete impl overriding eval
v, err := call.eval(env) Defensive patterns
Strategy: validation
Validate before calling
// Ensure the expression is a concrete call before evaluating
func isConcreteCall(e evalengine.IR) bool {
_, isBare := e.(*evalengine.CallExpr)
return !isBare
} Type guard
type concreteCall interface { evalengine.IR; callable() []evalengine.IR }
func asConcreteCall(e evalengine.IR) (concreteCall, bool) {
cc, ok := e.(concreteCall)
return cc, ok && !isBareCallExpr(e)
} Try / catch
func safeEval(e evalengine.IR, env *evalengine.ExpressionEnv) (v evalengine.eval, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("eval panic: %v", r)
}
}()
return e.eval(env)
} Prevention
- Never instantiate CallExpr directly; use the translation/builtin-dispatch helpers
- Ensure every parsed function has a registered evalengine implementation
- Add rewrite validation that rejects unresolved CallExpr before execution
- Add tests that evaluate all supported SQL functions
When it happens
Trigger: Evaluating an expression tree where a bare *CallExpr (not one of its concrete wrappers) is present and ExpressionEnv evaluation reaches CallExpr.eval. This occurs if the plan compiler/rewriter failed to replace CallExpr with a concrete implementation before execution.
Common situations: Vitess development where a new builtin/function kind is parsed but not mapped to its concrete evalengine implementation; tests that construct CallExpr directly; inconsistent builds where rewriting rules were skipped.
Related errors
- malformed hex literal from parser
- bad unsigned integer type
- bad type aggregation for signed/unsigned types
- unreachable
- unhandled case: evalIsTruthy
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/68fb94b227850cd7.
Report an issue: GitHub.