risingwavelabs/risingwave · error

failed to lookup and evaluate the expression in `eval`

Error message

failed to lookup and evaluate the expression in `eval`

What it means

The batch `eval` path of the constant-lookup CASE expression iterates input rows and calls the `lookup!` macro for each datum. Any per-row failure (from a normal arm or the fallback) is converted into this single generic error, so the whole array evaluation fails with no detail about which row or sub-expression failed.

Source

Thrown at src/expr/impl/src/scalar/case.rs:232

        for i in 0..input_len {
            let datum = eval_result.datum_at(i);
            let (row, vis) = $input.row_at(i);

            // Check for visibility
            if !vis {
                builder.append_null();
                continue;
            }

            // Note that the `owned_row` here is extracted from input
            // rather than from `eval_result`
            let owned_row = row.into_owned_row();

            // Lookup and evaluate the current input datum
            if let Ok(datum) = lookup!($mode, $this, datum, &owned_row) {
                builder.append(datum.as_ref());
            } else {
                bail!("failed to lookup and evaluate the expression in `eval`");
            }
        }

        Ok(Arc::new(builder.finish()))
    }};
}

impl<E: SyncExpression> SyncExpression for ConstantLookupExpression<E> {
    fn eval(&self, input: &DataChunk) -> Result<ArrayRef> {
        eval_constant_lookup!(sync, self, input)
    }

    fn eval_row(&self, input: &OwnedRow) -> Result<Datum> {
        let datum = self.operand.eval_row(input)?;
        lookup!(sync, self, datum, input)
    }
}

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Make the inner then/else expressions total (COALESCE, NULLIF, safe casts) so no row can fail.
  2. Filter or sanitize problematic rows before the CASE expression.
  3. If diagnosing, evaluate the CASE per-row or via a debug path to surface the underlying error.

Example fix

// before
CASE id WHEN 1 THEN amount / qty ELSE 0 END
// after
CASE id WHEN 1 THEN amount / NULLIF(qty, 0) ELSE 0 END
Defensive patterns

Strategy: try-catch

Try / catch

match array_result {
    Err(e) if e.to_string().contains("failed to lookup and evaluate the expression in `eval`") => {
        // re-run per-row to isolate the failing row and arm
    }
    other => other?,
}

Prevention

When it happens

Trigger: Batch evaluation of a constant-lookup CASE where at least one row's matched arm or fallback expression returns Err, causing the entire eval to bail with this wrapper message.

Common situations: Bulk query or MV backfill where a few rows contain values that break a then/else sub-expression; debugging is hard because the root error is swallowed.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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