risingwavelabs/risingwave · error

StreamVectorIndexLookupJoin only support append only input

Error message

StreamVectorIndexLookupJoin only support append only input

What it means

StreamVectorIndexLookupJoin::new validates that the input of a stream vector index lookup join is append-only. RisingWave stream fragments must know the input never emits UPDATE/DELETE retraction records for this node; if the input's StreamKind is not AppendOnly, the constructor bails with this error instead of producing an invalid plan.

Solutions

  1. Rewrite the query so the join input is append-only (e.g. query an append-only source or MV that never deletes/updates rows).
  2. If input is an MV receiving updates, materialize an append-only derived table (e.g. filter/aggregation that is append-only) and join against that.
  3. Check the input's StreamKind before constructing the node and surface a user-friendly error suggesting append-only input.

Example fix

// before
let node = StreamVectorIndexLookupJoin::new(core)?; // bails if input not append-only
// after
assert!(core.input.stream_kind() == StreamKind::AppendOnly, "vector index lookup join requires append-only input");
let node = StreamVectorIndexLookupJoin::new(core)?;
Defensive patterns

Strategy: validation

Validate before calling

if core.input.stream_kind() != StreamKind::AppendOnly {
    return Err(anyhow!("vector index lookup join requires an append-only input"));
}
let node = StreamVectorIndexLookupJoin::new(core)?;

Type guard

fn is_append_only(plan: &StreamPlanRef) -> bool { plan.stream_kind() == StreamKind::AppendOnly }

Prevention

When it happens

Trigger: Calling StreamVectorIndexLookupJoin::new with a core whose core.input.stream_kind() != StreamKind::AppendOnly, i.e. planning a vector index lookup join over a stream input that can produce retractions (e.g. an MV with upserts/deletes or a non-append-only source).

Common situations: Building queries that use vector index time travel/lookup joins on top of mutable tables or sources with updates; users attempt AS OF joins over frequently updated MVs where only append-only streams are supported.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/09db13299b11d470. Report an issue: GitHub.

Appendix: source

Thrown at src/frontend/src/optimizer/plan_node/stream_vector_index_lookup_join.rs:39

use crate::optimizer::plan_node::generic::{PhysicalPlanRef, VectorIndexLookupJoin};
use crate::optimizer::plan_node::stream::StreamPlanNodeMetadata;
use crate::optimizer::plan_node::utils::{Distill, childless_record};
use crate::optimizer::plan_node::{
    ExprRewritable, PlanBase, PlanTreeNodeUnary, Stream, StreamNode, StreamPlanRef,
};
use crate::optimizer::property::StreamKind;
use crate::stream_fragmenter::BuildFragmentGraphState;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StreamVectorIndexLookupJoin {
    pub base: PlanBase<Stream>,
    pub core: VectorIndexLookupJoin<StreamPlanRef>,
}

impl StreamVectorIndexLookupJoin {
    pub fn new(core: VectorIndexLookupJoin<StreamPlanRef>) -> crate::error::Result<Self> {
        if core.input.stream_kind() != StreamKind::AppendOnly {
            bail!("StreamVectorIndexLookupJoin only support append only input")
        }
        Ok(Self::with_core(core))
    }

    fn with_core(core: VectorIndexLookupJoin<StreamPlanRef>) -> Self {
        assert_eq!(core.input.stream_kind(), StreamKind::AppendOnly);
        let base = PlanBase::new_stream_with_core(
            &core,
            core.input.distribution().clone(),
            core.input.stream_kind(),
            core.input.emit_on_window_close(),
            core.input.watermark_columns().clone(),
            core.input.columns_monotonicity().clone(),
        );
        Self { base, core }
    }
}

View on GitHub (pinned to 6469eb736d)