{"record":{"id":"0152777fa0e474a3","repo":"influxdata/influxdb","slug":"at-least-one-expr","errorCode":null,"errorMessage":"at least one expr","messagePattern":"at least one expr","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/predicate/src/rpc_predicate/field_rewrite.rs","lineNumber":76,"sourceCode":"\n    /// Rewrites the predicate. See the description on\n    /// [`FieldProjectionRewriter`] for more details.\n    pub(crate) fn rewrite_field_exprs(\n        &mut self,\n        expr: Expr,\n    ) -> DataFusionResult<Transformed<Expr>> {\n        // for predicates like `A AND B AND C`\n        // rewrite `A`, `B` and `C` separately and put them back together\n        let rewritten_expr = split_conjunction_owned(expr)\n            .into_iter()\n            // apply the rewrite individually\n            .map(|expr| self.rewrite_single_conjunct(expr))\n            // check for errors\n            .collect::<DataFusionResult<Vec<Expr>>>()?\n            // put the Exprs back together with AND\n            .into_iter()\n            .reduce(|acc, expr| acc.and(expr))\n            .expect(\"at least one expr\");\n\n        Ok(Transformed::yes(rewritten_expr))\n    }\n\n    // Rewrites a single predicate. Does not handle AND specially\n    fn rewrite_single_conjunct(&mut self, expr: Expr) -> DataFusionResult<Expr> {\n        let mut finder = ColumnReferencesFinder::default();\n        expr.visit(&mut finder)?;\n\n        // rewrite any expression that only references _field to `true`\n        match (finder.saw_field_reference, finder.saw_non_field_reference) {\n            // Only saw _field column references, rewrite\n            (true, false) => {\n                self.field_predicates.push(expr);\n                Ok(lit(true))\n            }\n            // saw both _field and other column references, can't handle this case yet\n            // https://github.com/influxdata/influxdb_iox/issues/5310","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/core/predicate/src/rpc_predicate/field_rewrite.rs#L58-L94","documentation":"`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).","triggerScenarios":"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().","commonSituations":"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.","solutions":["Guard the caller: skip rewriting (or short-circuit to true) when the predicate is empty or has no conjuncts","Inspect how the predicate was parsed — an empty predicate should not reach rewrite_field_exprs","Fix the conjunct-splitting function so a literal-true predicate yields at least one expr","Replace the expect with reduce_initial or a fallback returning Transformed::no(orig_expr)"],"exampleFix":"// before\n.reduce(|acc, expr| acc.and(expr))\n.expect(\"at least one expr\");\n// after\nmatch conjuncts {\n    [] => Transformed::no(orig_expr),\n    [one] => Transformed::yes(one.clone()),\n    many => Transformed::yes(many.iter().cloned().fold(Expr::Literal(true), |a, e| a.and(e))),\n}","handlingStrategy":"validation","validationCode":"// caller-side guard before normalize_predicate\nif predicate.expr() == &Expr::Literal(ScalarValue::Boolean(Some(true))) || predicate_is_empty(&predicate) {\n    return Ok(predicate); // nothing to rewrite\n}","typeGuard":null,"tryCatchPattern":"// this is a panic (expect), not a catchable error; guard instead\n// wrap calls during diagnosis:\nlet result = std::panic::catch_unwind(|| rewriter.rewrite(expr.clone()));\nmatch result { Ok(t) => t, Err(_) => /* fall back to original expr */ }","preventionTips":["Skip rewriting for empty or literal-true predicates","Make the conjunct-splitting function always return at least one expr","Prefer reduce with an initial value (fold) over reduce+expect","Add unit tests for degenerate predicates (empty, literal true/false)"],"tags":["panic","empty-input","predicate","datafusion"],"backgroundTag":"empty-required-field","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}