risingwavelabs/risingwave · error

unknown fill strategy

Error message

unknown fill strategy: {}

What it means

The EOWC (emit-on-window-close) gap fill conversion validates each fill strategy string from the proto node against the known set: "locf", "interpolate", "null". Any other string fails conversion in `new_boxed_executor` with this error naming the unknown value.

Solutions

  1. Use one of the supported strategies: locf, interpolate, or null.
  2. Upgrade the stream compute node so its FillStrategy enum matches the frontend's emitted values.
  3. Inspect the fragment proto to find which strategy string is being sent and correct the query/planner.

Example fix

-- before
GAP FILL (FILL-strategy 'linear')
-- after
GAP FILL (... FILL ('locf')) -- or 'interpolate' / 'null'
Defensive patterns

Strategy: validation

Validate before calling

// before sending the proto
const VALID: [&str; 3] = ["locf", "interpolate", "null"];
assert!(strategies.iter().all(|s| VALID.contains(&s.as_str())), "unknown fill strategy");

Type guard

fn is_valid_strategy(s: &str) -> bool {
    matches!(s, "locf" | "interpolate" | "null")
}

Prevention

When it happens

Trigger: A `FillNode`/gap-fill proto carries a fill strategy string other than locf/interpolate/null, so the `match s.as_str()` arm hits the `_ => bail!` branch during actor building.

Common situations: Frontend (newer version) emitting a fill strategy the stream node (older version) does not know; a typo or corrupt value in the plan proto; hand-crafted test plans with bogus strategy strings.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src/stream/src/from_proto/eowc_gap_fill.rs:65

        // Parse interval from ExprNode
        let interval_expr_node = node.get_interval()?;
        let gap_interval =
            build_non_strict_from_prost(interval_expr_node, params.eval_error_report.clone())?;

        let fill_columns: Vec<usize> = node
            .get_fill_columns()
            .iter()
            .map(|&x| x as usize)
            .collect();

        let fill_strategies: Vec<FillStrategy> = node
            .get_fill_strategies()
            .iter()
            .map(|s| match s.as_str() {
                "locf" => Ok(FillStrategy::Locf),
                "interpolate" => Ok(FillStrategy::Interpolate),
                "null" => Ok(FillStrategy::Null),
                _ => anyhow::bail!("unknown fill strategy: {}", s),
            })
            .collect::<anyhow::Result<_>>()?;

        let fill_columns_with_strategies: HashMap<usize, FillStrategy> =
            fill_columns.into_iter().zip_eq(fill_strategies).collect();

        let vnodes = params.vnode_bitmap.map(Arc::new);

        let prev_row_table =
            StateTableBuilder::new(node.get_prev_row_table().as_ref().unwrap(), store, vnodes)
                .forbid_preload_all_rows()
                .build()
                .await;

        let partition_by_indices: Vec<usize> = node
            .get_partition_by_indices()
            .iter()
            .map(|&x| x as usize)

View on GitHub (pinned to 6469eb736d)