{"record":{"id":"f3b001cc5e240be3","repo":"risingwavelabs/risingwave","slug":"in-set-expression-must-be-sync","errorCode":null,"errorMessage":"IN set expression must be sync","messagePattern":"IN set expression must be sync","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/scalar/in_.rs","lineNumber":120,"sourceCode":"impl<E: AsyncExpression> AsyncExpression for InExpression<E> {\n    async fn eval(&self, input: &DataChunk) -> Result<ArrayRef> {\n        eval_in!(async, self, input)\n    }\n\n    async fn eval_row(&self, input: &OwnedRow) -> Result<Datum> {\n        eval_row_in!(async, self, input)\n    }\n}\n\n#[build_function(\"in(any, ...) -> boolean\")]\nfn build(return_type: DataType, children: Vec<BoxedExpression>) -> Result<BoxedExpression> {\n    let mut iter = children.into_iter();\n    let left_expr = iter.next().unwrap();\n    let mut data = Vec::with_capacity(iter.size_hint().0);\n    let data_chunk = DataChunk::new_dummy(1);\n    for child in iter {\n        let BoxedExpression::Sync(child) = child else {\n            bail!(\"IN set expression must be sync\")\n        };\n        let array = child.eval(&data_chunk)?;\n        let datum = array.value_at(0).to_owned_datum();\n        data.push(datum);\n    }\n    Ok(match left_expr {\n        BoxedExpression::Sync(left_expr) => {\n            InExpression::new(left_expr, data.into_iter(), return_type).boxed()\n        }\n        left_expr @ BoxedExpression::Async(_) => {\n            InExpression::new(left_expr, data.into_iter(), return_type).boxed()\n        }\n    })\n}\n\n#[cfg(test)]\nmod tests {\n    use risingwave_common::array::DataChunk;","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/scalar/in_.rs#L102-L138","documentation":"During constant folding of an IN expression, RisingWave evaluates every element of the IN set as a constant so the whole predicate can be reduced. Each set element expression must implement the Sync marker because it is evaluated inside a non-async context (and may be shared across threads); an element that is not `Sync` cannot be safely evaluated here, so the builder bails out instead of risking unsound evaluation.","triggerScenarios":"Calling `new_in_expr` (IN expression construction) where one of the child expressions after the first (the left operand) is a `BoxedExpression` that does not implement `Sync`, e.g. a non-thread-safe expression type wrapped in the box.","commonSituations":"Custom or internal expression implementations that hold `Rc`, raw pointers, or non-Sync references; hitting this after writing a custom scalar expression or when a new expression variant forgets to be thread-safe while being usable as an IN-set constant.","solutions":["Make the child expression type `Sync` (replace `Rc` with `Arc`, remove non-Sync interior mutability)","Check which expression variant is in the IN set and ensure it implements `Sync`/`Send`","If the element genuinely cannot be sync, avoid putting it in an IN set constant-fold path (keep the generic IN evaluation instead of the specialized builder)"],"exampleFix":"// before\nstruct MyExpr { inner: Rc<RefCell<State>> }\n// after\nstruct MyExpr { inner: Arc<State> }","handlingStrategy":"type-guard","validationCode":"// assert all IN-set children are Sync at compile time: fn assert_sync<T: Sync>() {} assert_sync::<BoxedExpression>();","typeGuard":"fn is_sync(e: &BoxedExpression) -> bool { let _: &dyn Sync = unsafe { std::mem::transmute(e) }; true } // prefer compile-time T: Sync bounds","tryCatchPattern":"match new_in_expr(...) { Err(e) if e.to_string().contains(\"must be sync\") => { /* fall back to generic IN evaluation */ }, r => r? }","preventionTips":["Use Arc instead of Rc in expression internals","Run clippy/miri checks for Send/Sync on expression types","Add compile-time assertions for Sync on all expression variants"],"tags":["rust","expressions","concurrency"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}