tursodatabase/turso · error
Unsupported operator in trivial expression: {op:?}
Error message
Unsupported operator in trivial expression: {op:?} What it means
The incremental-maintenance expression compiler can lower 'trivial' binary expressions to a fast path, but TrivialExpression::evaluate only implements Add, Subtract, Multiply and Divide (via Value::exec_*). Any other Operator reaching this match panics - the analyzer/lowering admitted an expression the evaluator cannot run.
Source
Thrown at core/incremental/expr_compiler.rs:132
impl TrivialExpression {
/// Evaluate the trivial expression with the given input values
/// Automatically promotes integers to floats when mixing types in arithmetic
pub fn evaluate(&self, values: &[Value]) -> Value {
match self {
TrivialExpression::Column(idx) => values.get(*idx).cloned().unwrap_or(Value::Null),
TrivialExpression::Immediate(val) => val.clone(),
TrivialExpression::Binary { left, op, right } => {
let left_val = left.evaluate(values);
let right_val = right.evaluate(values);
// Use Value's exec_* methods which handle all type coercion
// (including Text → Numeric) consistently with SQLite semantics
match op {
Operator::Add => left_val.exec_add(&right_val),
Operator::Subtract => left_val.exec_subtract(&right_val),
Operator::Multiply => left_val.exec_multiply(&right_val),
Operator::Divide => left_val.exec_divide(&right_val),
_ => panic!("Unsupported operator in trivial expression: {op:?}"),
}
}
}
}
}
/// Compiled expression that can be executed on row values
#[derive(Clone)]
pub struct CompiledExpression {
/// The expression executor (trivial or compiled)
pub executor: ExpressionExecutor,
/// Number of input values expected (columns from the row)
pub input_count: usize,
}
impl std::fmt::Debug for CompiledExpression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = f.debug_struct("CompiledExpression");View on GitHub (pinned to 492c4a71cd)
Solutions
- Restrict incremental-maintained expressions to +, -, *, / until the operator is supported
- If you maintain the compiler, keep the analyzer whitelist in sync with the operators handled in evaluate()
- Report or add support for the specific operator with a minimal SQL repro
Example fix
-- before CREATE MATERIALIZED VIEW v AS SELECT (n % 10) AS bucket FROM t; -- modulo has no trivial path -- after CREATE MATERIALIZED VIEW v AS SELECT (n / 10) AS decade FROM t; -- division is supported
Defensive patterns
Strategy: type-guard
Validate before calling
fn is_trivial_op(op: &Operator) -> bool {
matches!(op, Operator::Add | Operator::Subtract | Operator::Multiply | Operator::Divide)
}
// reject anything else before lowering to TrivialExpression Type guard
fn is_trivial_expression(e: &TrivialExpression) -> bool {
match e {
TrivialExpression::Immediate(_) => true,
TrivialExpression::Binary { op, .. } => matches!(
op,
Operator::Add | Operator::Subtract | Operator::Multiply | Operator::Divide
),
}
} Prevention
- Keep the analyzer whitelist and the evaluator match in the same change/review
- Add a unit test enumerating operators accepted by lowering versus handled by evaluate()
When it happens
Trigger: Creating incrementally-maintained structures in core/incremental whose expression uses an operator outside + - * / (e.g. %, ||, <<, comparisons); or a lowering change that routes wider expression classes into TrivialExpression.
Common situations: Writing new incremental view definitions with rich expressions; analyzer refactors that widen the trivial-expression filter without extending evaluate().
Related errors
- Cursor not found: {key:?}
- buffer not loaded
- OpenRead on pseudo cursor
- Rewind on non-btree/materialized-view cursor
- unexpected cursor type
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/b6c81e518d851bca.
Report an issue: GitHub.