risingwavelabs/risingwave · error
should be append-only for vector index writer but receive op
Error message
should be append-only for vector index writer but receive op {:?} What it means
The vector index writer only accepts append-only input; each row in an incoming chunk must have op `Insert`. Any Delete or Update op causes `execute_inner` to return this error with the offending op for diagnosis.
Solutions
- Restrict the vector table to INSERT-only writes; model changes as new inserts.
- Verify upstream sources are append-only (no upsert CDC configured).
- Rebuild the vector index from scratch if historical mutations must be applied.
Example fix
-- before DELETE FROM embeddings WHERE id = 1; -- after -- keep table append-only; filter stale rows at query time or rebuild the index
Defensive patterns
Strategy: validation
Validate before calling
-- application-side check before writing -- only issue INSERT statements against the vector index input table
Prevention
- Configure upstream as an append-only source
- Model corrections as new inserts, not updates
- Filter stale rows at query time rather than deleting them
When it happens
Trigger: A chunk row with `Op::Delete`, `Op::UpdateDelete`, or `Op::UpdateInsert` reaches the vector index writer in `execute_inner`, e.g. an upstream table mutation (UPDATE/DELETE) that must be reflected into the vector index.
Common situations: Updating or deleting embeddings after they were written; CDC/upsert sources feeding a vector index; mistaken use of a non-append-only materialized view as the vector index input.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- streaming vector index lookup join only support append-only…
- StreamVectorIndexLookupJoin only support append only input
- a stream has reached the end but some other stream has not…
- Actor exited unexpectedly
- actor exited unexpectedly
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/60e703dd21711937.
Report an issue: GitHub.
Appendix: source
Thrown at src/stream/src/executor/vector/index_writer.rs:86
.await?;
while let Some(msg) = input.try_next().await? {
match msg {
Message::Barrier(barrier) => {
self.vector_writer.flush().await?;
self.vector_writer.seal_current_epoch(
barrier.epoch.curr,
SealCurrentEpochOptions {
table_watermarks: None,
switch_op_consistency_level: None,
},
);
yield Message::Barrier(barrier);
}
Message::Chunk(chunk) => {
for (op, row) in chunk.rows() {
if op != Op::Insert {
return Err(anyhow!(
"should be append-only for vector index writer but receive op {:?}",
op
)
.into());
}
let vector_datum = row.datum_at(0);
let Some(vector_datum) = vector_datum else {
warn!(
?row,
"vector index writer received a row with null vector datum, skipping"
);
continue;
};
let vector = vector_datum.into_vector();
let info = self
.serializer
.serialize(row.project(&info_column_indices))
.into();View on GitHub (pinned to 6469eb736d)