risingwavelabs/risingwave · error
Conditions containing now must be in the form of…
Error message
Conditions containing now must be in the form of `input_expr cmp now_expr` or `now_expr cmp input_expr`, where `input_expr` references a column and contains no `now()`, and `now_expr` is a non-decreasing expression contains `now()`.
What it means
`check_stream_predicate` validates that any predicate containing `now()` is streamable. Only the strict forms `input_expr cmp now_expr` or `now_expr cmp input_expr` (input side referencing a column without now(); now side a non-decreasing now()-containing expression) are supported by temporal filtering; anything else containing `now()` is rejected with this bail.
Solutions
- Rewrite the condition so now() appears alone on one side of the comparison: `created_at > now() - interval '1 hour'` becomes an arrangement-friendly form by isolating now(), e.g. `now() < created_at + interval '1 hour'` only if the right side is non-decreasing; otherwise restructure.
- Ensure the non-now side references a column and contains no now().
- Move complex now()-based logic to query-time filters in batch queries, or use a refresh-scheduled materialized view pattern instead.
Example fix
-- before CREATE MATERIALIZED VIEW mv AS SELECT * FROM events WHERE created_at > now() - INTERVAL '1 hour'; -- after (isolate now() on one side) CREATE MATERIALIZED VIEW mv AS SELECT * FROM events WHERE now() - INTERVAL '1 hour' < created_at -- or restructure to `now() < created_at + INTERVAL '1 hour'` if valid and non-decreasing;
Defensive patterns
Strategy: validation
Validate before calling
fn is_now_stream_safe(cond: &Expr) -> bool {
if !cond.has_now() { return true; }
matches!(
cond.as_comparison(),
Some((lhs, _)) | Some((_, rhs))
if lhs.references_column_only() && !lhs.has_now()
|| rhs.references_column_only() && !rhs.has_now()
)
} Try / catch
match LogicalFilter::check_stream_predicate(&pred) {
Err(e) => {
eprintln!("predicate not streamable: {e}; isolate now() on one side of cmp");
return Err(e);
}
Ok(()) => proceed(),
} Prevention
- Keep now() isolated on one side of comparisons in streaming predicates
- Never embed now() in arithmetic on the column side
- Test MV DDL with now()-filters before deploying
- Prefer batch queries for complex time-based filters
When it happens
Trigger: Creating a materialized view or streaming query whose WHERE/JOIN condition contains `now()` in a non-conforming form, e.g. `now() - interval '5 minutes' > created_at` with the now-expression embedded in arithmetic, or `now() + a > b` where a side mixes columns and now().
Common situations: Users write time-window style filters like `WHERE created_at > now() - INTERVAL '1 hour'` on materialized views; the form must be rewritten because the now-expression is inside subtraction.
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
- Actor exited unexpectedly
- Array error
- below watermark check condition eval must return bool array
- Chunk operation error
- clean watermark column index
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/7369701dfc5db916.
Report an issue: GitHub.
Appendix: source
Thrown at src/frontend/src/optimizer/plan_node/logical_filter.rs:60
pub struct LogicalFilter {
pub base: PlanBase<Logical>,
core: generic::Filter<PlanRef>,
}
impl LogicalFilter {
pub fn new(input: PlanRef, predicate: Condition) -> Self {
let _ctx = input.ctx();
for cond in &predicate.conjunctions {
assert_input_ref!(cond, input.schema().fields().len());
}
let core = generic::Filter { predicate, input };
let base = PlanBase::new_logical_with_core(&core);
LogicalFilter { base, core }
}
pub fn check_stream_predicate(predicate: &Condition) -> Result<()> {
if predicate.conjunctions.iter().any(|cond| cond.has_now()) {
bail!(
"Conditions containing now must be in the form of `input_expr cmp now_expr` or \
`now_expr cmp input_expr`, where `input_expr` references a column and contains \
no `now()`, and `now_expr` is a non-decreasing expression contains `now()`."
);
}
Ok(())
}
/// Create a `LogicalFilter` unless the predicate is always true
pub fn create(input: PlanRef, predicate: Condition) -> PlanRef {
if predicate.always_true() {
input
} else {
LogicalFilter::new(input, predicate).into()
}
}
/// Create a `LogicalFilter` to filter out rows where all keys are null.View on GitHub (pinned to 6469eb736d)