risingwavelabs/risingwave · error

streaming vector index lookup join must be proctime…

Error message

streaming vector index lookup join must be proctime temporal join

What it means

Raised in LogicalVectorSearchLookupJoin::to_stream when the temporal join is not an AS OF PROCTIME join. Streaming vector-index lookup joins are only defined against the current processing time; other temporal join variants (event-time AS OF) cannot use the lookup executor, so the plan is rejected.

Solutions

  1. Define the temporal join in the streaming vector index lookup as a process-time (NOW() AS OF) temporal join.
  2. Use the standard temporal join syntax with process time on the lookup side.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at src/frontend/src/optimizer/plan_node/logical_vector_search_lookup_join.rs:306 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at src/frontend/src/optimizer/plan_node/logical_vector_search_lookup_join.rs:306

            .is_identity()
        {
            // TODO: support it
            bail!(
                "LogicalVectorSearchLookupJoin does not support input that can possibly be rewritten"
            )
        }
        Ok((
            self.clone().into(),
            ColIndexMapping::identity(self.base.schema().len()),
        ))
    }

    fn to_stream(&self, ctx: &mut ToStreamContext) -> Result<StreamPlanRef> {
        if let Some(core) = self.to_vector_index_lookup_join(|plan| plan.to_stream(ctx))? {
            // `ProcessTimeBroadcast` is intentionally excluded: the vector-index lookup executor
            // does not consume a broadcast change stream or maintain replicated lookup state.
            if !matches!(&core.as_of, Some(AsOf::ProcessTime)) {
                bail!("streaming vector index lookup join must be proctime temporal join");
            }
            return Ok(StreamVectorIndexLookupJoin::new(core)?.into());
        }
        bail!("LogicalVectorSearchLookupJoin should use proper vector index in streaming job")
    }
}

impl LogicalVectorSearchLookupJoin {
    pub(crate) fn as_index_lookup(&self) -> Option<(&Arc<VectorIndex>, Vec<usize>, Option<AsOf>)> {
        if let Some(scan) = self.core.lookup.as_logical_scan()
            && let Some((
                index,
                _covered_table_cols_idx,
                non_covered_table_cols_idx,
                primary_table_col_in_output,
            )) = LogicalVectorSearch::resolve_vector_index_lookup(
                scan,
                &self.core.lookup_vector,

View on GitHub (pinned to 6469eb736d)