{"record":{"id":"6689405d50a60a2d","repo":"pingcap/tidb","slug":"tiflash-does-not-support-vector-index-with-pedicat","errorCode":null,"errorMessage":"TiFlash does not support vector index with pedicates","messagePattern":"TiFlash does not support vector index with pedicates","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/planner/core/operator/physicalop/tiflash_predicate_push_down.go","lineNumber":281,"sourceCode":"\n// handleTiFlashPredicatePushDown is used to handle the TiFlash predicate push down.\n// 1. Whether to use the inverted index.\n// 2. Whether to push down the conditions to the table scan.\nfunc handleTiFlashPredicatePushDown(pctx base.PlanContext, ts *PhysicalTableScan, indexHints []*ast.IndexHint) {\n\t// When the table is small, there is no need to push down the conditions.\n\tif ts.TblColHists.RealtimeCount <= tiflashDataPackSize || ts.KeepOrder || len(ts.FilterCondition) == 0 {\n\t\treturn\n\t}\n\n\t// Currently, TiFlash does not support vector index with predicates.\n\t// So for now, one DataSource only contains one TiFlash !keepOrder path,\n\t// which means that the following code will only be executed once.\n\t// TODO: If there are multiple TiFlash !keepOrder paths in one DataSource in the future,\n\t// we need to move the following code to another place.\n\t// Since caculating selectivity is expensive, we need to avoid duplicate execution.\n\tfor _, index := range ts.UsedColumnarIndexes {\n\t\tif index.IndexInfo.VectorInfo != nil {\n\t\t\tpanic(\"TiFlash does not support vector index with pedicates\")\n\t\t}\n\t}\n\n\t// Consider use index hints\n\tindexMap := make(map[string]int, len(ts.Table.Indices))\n\tfor _, hint := range indexHints {\n\t\tif hint.HintScope != ast.HintForScan {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch hint.HintType {\n\t\tcase ast.HintUse:\n\t\t\tfor _, name := range hint.IndexNames {\n\t\t\t\tif indexMap[name.L] != math.MaxInt {\n\t\t\t\t\tindexMap[name.L]++\n\t\t\t\t}\n\t\t\t}\n\t\tcase ast.HintIgnore:","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/pingcap/tidb/blob/d01f9615c13e02dfa75922745640dec9d81b802e/pkg/planner/core/operator/physicalop/tiflash_predicate_push_down.go#L263-L299","documentation":"A planner assertion in tiflash_predicate_push_down.go: for a large table (RealtimeCount > tiflashDataPackSize), not KeepOrder, with non-empty FilterCondition - i.e. predicates would be pushed to a TiFlash scan - the code verifies no used columnar index is a vector index, because TiFlash cannot serve a vector index scan together with predicates. If ts.UsedColumnWith VectorInfo is found it panics (message typo 'pedicates' included) rather than generating an unsupported plan.","triggerScenarios":"A SELECT over a table with a VECTOR index where the planner both keeps the vector index as a UsedColumnarIndexes entry AND pushes a WHERE predicate into the TiFlash !KeepOrder path - normally prevented upstream by forcing vector-index plans to bypass this path (e.g. via VECTOR_INDEX hints on filtered queries). Reaching the panic means the guard failed, typically a planner bug.","commonSituations":"Using a vector index (ANN search) together with additional WHERE filters in versions where the vector-index-with-predicates plan path was incomplete (feature in preview/beta); index hints like /*+ USE_VECTOR_INDEX(...) */ combined with filters forcing the predicate-push-down branch; upgrading TiDB and hitting a regression in the vector index plan pruning.","solutions":["Upgrade TiDB to a version where vector index plus predicate handling is complete and this invariant cannot be violated.","Rewrite the query so predicates and the vector index do not share one plan: do the vector search into a subquery/CTE and apply filters outside it.","Remove any index hints (USE_INDEX / USE_VECTOR_INDEX / read_from_storage hints) that force the vector index on the filtered scan.","If it reproduces without hints on the latest version, report it at github.com/pingcap/tidb with the query, table schema, and EXPLAIN output."],"exampleFix":"-- before: filter + vector index in one scan can trip the planner assertion\nSELECT id FROM docs WHERE content_vec <@ '[1,2,3]' AND category = 5 LIMIT 10;\n\n-- after: isolate the ANN search, then filter\nWITH ann AS (\n  SELECT id FROM docs ORDER BY content_vec <@ '[1,2,3]' LIMIT 100\n)\nSELECT a.id FROM ann a JOIN docs d ON d.id = a.id WHERE d.category = 5;","handlingStrategy":"validation","validationCode":"-- before relying on a vector index with filters, check plan shape: the ANN scan\n-- must appear as a separate TABLE_SCAN/VectorScan without pushed predicates\nEXPLAIN SELECT id FROM docs WHERE content_vec <@ '[1,2,3]' AND category = 5;\n-- if predicates sit on the same TiFlash scan as the vector index, rewrite the query","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Isolate vector (ANN) searches in a subquery/CTE and filter outside it.","Do not attach USE_VECTOR_INDEX / USE_INDEX hints to filtered queries over vector tables.","Keep TiDB (and TiFlash) on versions where vector-index-with-predicates is fully supported.","EXPLAIN new vector queries in staging before production."],"tags":["tidb","planner","tiflash","vector-index","panic"],"backgroundTag":null,"analyzedSha":"d01f9615c13e02dfa75922745640dec9d81b802e","analyzedAt":"2026-08-15T12:19:33.324Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}