{"record":{"id":"d6f598a5b37236df","repo":"risingwavelabs/risingwave","slug":"streaming-vector-index-lookup-join-only-support-ap","errorCode":null,"errorMessage":"streaming vector index lookup join only support append-only input","messagePattern":"streaming vector index lookup join only support append-only input","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/executor/vector/index_lookup_join.rs","lineNumber":82,"sourceCode":"            .new_snapshot(HummockReadEpoch::Committed(first_epoch.prev))\n            .await?;\n\n        while let Some(msg) = input.try_next().await? {\n            match msg {\n                Message::Barrier(barrier) => {\n                    let is_checkpoint = barrier.is_checkpoint();\n                    let prev_epoch = barrier.epoch.prev;\n                    yield Message::Barrier(barrier);\n                    if is_checkpoint {\n                        read_snapshot = reader\n                            .new_snapshot(HummockReadEpoch::Committed(prev_epoch))\n                            .await?;\n                    }\n                }\n                Message::Chunk(chunk) => {\n                    let (chunk, ops) = chunk.into_parts();\n                    if ops.iter().any(|op| *op != Op::Insert) {\n                        bail!(\"streaming vector index lookup join only support append-only input\");\n                    }\n                    let chunk = read_snapshot\n                        .query_expand_chunk(chunk, vector_column_idx)\n                        .await?;\n                    yield Message::Chunk(StreamChunk::from_parts(ops, chunk));\n                }\n                Message::Watermark(watermark) => {\n                    yield Message::Watermark(watermark);\n                }\n            }\n        }\n    }\n}\n","sourceCodeStart":64,"sourceCodeEnd":96,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/executor/vector/index_lookup_join.rs#L64-L96","documentation":"The vector index lookup join executor reads from the append-only vector source's snapshot-read side and cannot process updates or deletes: any chunk containing an op other than `Op::Insert` aborts with this error. Vector index structures assume append-only input for correctness of lookups.","triggerScenarios":"A chunk with `UpdateDelete`, `UpdateInsert`, or `Delete` ops arrives at the lookup-join read side during `execute_inner`, e.g. the upstream vector table receives UPDATE or DELETE statements while a vector index lookup join is consuming it.","commonSituations":"Running `UPDATE`/`DELETE` (or `UPDATE` via upsert semantics) on the embedding table feeding a vector index; CDC sources that emit update/delete events; users assuming the vector table is mutable like a normal table.","solutions":["Use only INSERT (append-only) workloads on the vector source table; recreate rows instead of updating them.","Declare/check the source as append-only so writes violating it are rejected at ingest time.","If mutations are required, drop and rebuild the vector index/table from an append-only re-ingestion."],"exampleFix":"-- before\nUPDATE embeddings SET vec = new_vec WHERE id = 1;\n-- after\nINSERT INTO embeddings (id, vec) VALUES (1, new_vec); -- append-only model","handlingStrategy":"validation","validationCode":"-- ensure the source is append-only before creating a vector index lookup join\n-- reject UPDATE/DELETE on the vector table in your application layer","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat vector/embedding tables as append-only","Avoid CDC sources with update/delete events for vector indexes","Rebuild the index instead of mutating existing embeddings"],"tags":["streaming","vector-index","append-only"],"backgroundTag":"unsupported-operation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}