influxdata/influxdb · error

at least one expr

Error message

at least one expr

What it means

`rewrite_field_exprs` uses `.reduce(|acc, expr| acc.and(expr)).expect("at least one expr")`, which panics if the iterator of rewritten conjuncts is empty. The iterator comes from splitting the predicate into conjuncts, so it panics only when a predicate yields zero conjuncts (e.g. an empty/`Literal(true)`-stripped expression).

Solutions

  1. Guard the caller: skip rewriting (or short-circuit to true) when the predicate is empty or has no conjuncts
  2. Inspect how the predicate was parsed — an empty predicate should not reach rewrite_field_exprs
  3. Fix the conjunct-splitting function so a literal-true predicate yields at least one expr
  4. Replace the expect with reduce_initial or a fallback returning Transformed::no(orig_expr)

Example fix

// before
.reduce(|acc, expr| acc.and(expr))
.expect("at least one expr");
// after
match conjuncts {
    [] => Transformed::no(orig_expr),
    [one] => Transformed::yes(one.clone()),
    many => Transformed::yes(many.iter().cloned().fold(Expr::Literal(true), |a, e| a.and(e))),
}
Defensive patterns

Strategy: validation

Validate before calling

// caller-side guard before normalize_predicate
if predicate.expr() == &Expr::Literal(ScalarValue::Boolean(Some(true))) || predicate_is_empty(&predicate) {
    return Ok(predicate); // nothing to rewrite
}

Try / catch

// this is a panic (expect), not a catchable error; guard instead
// wrap calls during diagnosis:
let result = std::panic::catch_unwind(|| rewriter.rewrite(expr.clone()));
match result { Ok(t) => t, Err(_) => /* fall back to original expr */ }

Prevention

When it happens

Trigger: Calling normalize_predicate / FieldColumnRewriter with a predicate expression whose conjunct list is empty after splitting — e.g. a predicate that is just `TRUE`/empty, or upstream splitting producing Vec::new().

Common situations: Passing default/empty predicates through the field-rewrite path; upstream changes to conjunction splitting that now emit zero exprs; InfluxQL/SQL translation producing degenerate predicates.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19). Data as JSON: /api/errors/0152777fa0e474a3. Report an issue: GitHub.

Appendix: source

Thrown at core/predicate/src/rpc_predicate/field_rewrite.rs:76

    /// Rewrites the predicate. See the description on
    /// [`FieldProjectionRewriter`] for more details.
    pub(crate) fn rewrite_field_exprs(
        &mut self,
        expr: Expr,
    ) -> DataFusionResult<Transformed<Expr>> {
        // for predicates like `A AND B AND C`
        // rewrite `A`, `B` and `C` separately and put them back together
        let rewritten_expr = split_conjunction_owned(expr)
            .into_iter()
            // apply the rewrite individually
            .map(|expr| self.rewrite_single_conjunct(expr))
            // check for errors
            .collect::<DataFusionResult<Vec<Expr>>>()?
            // put the Exprs back together with AND
            .into_iter()
            .reduce(|acc, expr| acc.and(expr))
            .expect("at least one expr");

        Ok(Transformed::yes(rewritten_expr))
    }

    // Rewrites a single predicate. Does not handle AND specially
    fn rewrite_single_conjunct(&mut self, expr: Expr) -> DataFusionResult<Expr> {
        let mut finder = ColumnReferencesFinder::default();
        expr.visit(&mut finder)?;

        // rewrite any expression that only references _field to `true`
        match (finder.saw_field_reference, finder.saw_non_field_reference) {
            // Only saw _field column references, rewrite
            (true, false) => {
                self.field_predicates.push(expr);
                Ok(lit(true))
            }
            // saw both _field and other column references, can't handle this case yet
            // https://github.com/influxdata/influxdb_iox/issues/5310

View on GitHub (pinned to 06200ef96b)