risingwavelabs/risingwave · error
unknown fill strategy
Error message
unknown fill strategy: {} What it means
Same family as the EOWC variant: the gap fill conversion maps each strategy string from the proto node to a `FillStrategy`, accepting only "locf", "interpolate", and "null"; anything else aborts `new_boxed_executor` with this message naming the string.
Solutions
- Use a supported fill strategy: locf, interpolate, or null.
- Align frontend and stream node versions so both support the same strategies.
- Inspect the plan proto for the offending strategy string and fix the source query/planner.
Example fix
-- before
FILL ('carry-forward')
-- after
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
- Use only locf/interpolate/null in FILL clauses
- Version-align frontend and stream components
- Validate plan protos in CI before deploying
When it happens
Trigger: A gap-fill proto node contains a fill strategy string outside the accepted set, so the `match s.as_str()` default arm bails while building the actor.
Common situations: Version skew between frontend emitting newer strategies and an older stream node; malformed or hand-edited plan protos; typos in strategy names in generated plans.
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
- unknown fill strategy
- Gap interval expression returned null
- Gap interval must be positive
- Time column should be Timestamp or Timestamptz
- a stream has reached the end but some other stream has not…
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/d0e2a20478a6ada4.
Report an issue: GitHub.
Appendix: source
Thrown at src/stream/src/from_proto/gap_fill.rs:63
// Parse interval from ExprNode
let interval_expr_node = node.get_interval()?;
let interval_expr =
build_non_strict_from_prost(interval_expr_node, params.eval_error_report)?;
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 partition_by_indices: Vec<usize> = node
.get_partition_by_indices()
.iter()
.map(|&x| x as usize)
.collect();
// Hash-distributed state table needs vnodes; singleton (no partition) does not.
let vnodes = if partition_by_indices.is_empty() {
None
} else {
Some(std::sync::Arc::new(
paramsView on GitHub (pinned to 6469eb736d)