{"record":{"id":"5e9f50f1ab29b38f","repo":"vitessio/vitess","slug":"vt09018-5e9f50","errorCode":"VT09018","errorMessage":" (where clause missing)","messagePattern":" \\(where clause missing\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/planbuilder/operators/vindex.go","lineNumber":121,"sourceCode":"func (v *Vindex) GetSelectExprs(ctx *plancontext.PlanningContext) []sqlparser.SelectExpr {\n\treturn transformColumnsToSelectExprs(ctx, v)\n}\n\nfunc (v *Vindex) GetOrdering(*plancontext.PlanningContext) []OrderBy {\n\treturn nil\n}\n\nfunc (v *Vindex) GetColNames() []*sqlparser.ColName {\n\treturn v.Columns\n}\n\nfunc (v *Vindex) AddCol(col *sqlparser.ColName) {\n\tv.Columns = append(v.Columns, col)\n}\n\nfunc (v *Vindex) CheckValid() {\n\tif len(v.Table.Predicates) == 0 {\n\t\tpanic(vterrors.VT09018(wrongWhereCond + \" (where clause missing)\"))\n\t}\n}\n\nfunc (v *Vindex) AddPredicate(ctx *plancontext.PlanningContext, expr sqlparser.Expr) Operator {\n\tfor _, e := range sqlparser.SplitAndExpression(nil, expr) {\n\t\tdeps := ctx.SemTable.RecursiveDeps(e)\n\t\tif deps.NumberOfTables() > 1 {\n\t\t\tpanic(vterrors.VT09018(wrongWhereCond + \" (multiple tables involved)\"))\n\t\t}\n\t\t// check if we already have a predicate\n\t\tif v.OpCode != engine.VindexNone {\n\t\t\tpanic(vterrors.VT09018(wrongWhereCond + \" (multiple filters)\"))\n\t\t}\n\n\t\t// check LHS\n\t\tcomparison, ok := e.(*sqlparser.ComparisonExpr)\n\t\tif !ok {\n\t\t\tpanic(vterrors.VT09018(wrongWhereCond + \" (not a comparison)\"))","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/planbuilder/operators/vindex.go#L103-L139","documentation":"VT09018 is raised by the Vindex operator's CheckValid when the routed table has no predicates. Vindex-based routing requires a WHERE condition (typically on the vindex column) to resolve shards; planning a SELECT/UPDATE/DELETE on the table without any WHERE clause makes the plan invalid. The message combines a shared 'wrong where condition' text with '(where clause missing)'.","triggerScenarios":"Building a plan for a query that targets a table through the Vindex operator whose v.Table.Predicates is empty when CheckValid() runs — i.e. no WHERE predicate was supplied or extracted.","commonSituations":"Issuing 'SELECT * FROM t' or a DML without WHERE and expecting vindex routing; an app framework stripping the WHERE clause; a developer testing a vindex-routed table without the required id filter.","solutions":["Add a WHERE clause with an equality/IN predicate on the vindex column, e.g. WHERE id = 5.","If a full scan is intended, do not use this vindex route (use a different routing path).","If you believe the predicate exists, verify it is a single-table comparison on the 'id' column that AddPredicate accepts."],"exampleFix":"// before\nSELECT * FROM user\n// after\nSELECT * FROM user WHERE id = 5","handlingStrategy":"validation","validationCode":"if len(op.Table.Predicates) == 0 {\n    return errors.New(\"vindex routing requires a WHERE clause\")\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if strings.Contains(fmt.Sprint(r), \"where clause missing\") {\n            return fmt.Errorf(\"query needs WHERE clause for vindex routing: %v\", r)\n        }\n        panic(r)\n    }\n}()","preventionTips":["Always include a WHERE predicate on the vindex column when routing by vindex","Validate user queries reject full-table operations on vindex-routed paths","Call CheckValid only after predicates have been added via AddPredicate"],"tags":["vitess","planbuilder","vindex-routing","missing-where"],"backgroundTag":"missing-where-clause-for-vindex","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}