{"record":{"id":"170bc1f85888af89","repo":"risingwavelabs/risingwave","slug":"async-child-in-iceberg-transform-is-not-supported","errorCode":null,"errorMessage":"async child in iceberg_transform is not supported","messagePattern":"async child in iceberg_transform is not supported","errorType":"error_code","errorClass":"Internal","httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/scalar/external/iceberg.rs","lineNumber":161,"sourceCode":"            (matches!(transform_type, Transform::Day) && matches!(actual_res_type, IcebergType::Primitive(PrimitiveType::Int))),\n        ExprError::InvalidParam {\n            name: \"return type in iceberg_transform\",\n            reason: format!(\n                \"Expect return type {:?} but got {:?}, RisingWave return type is {:?}, input type is {:?}, transform type is {:?}\",\n                expect_res_type,\n                actual_res_type,\n                return_type,\n                (input_type, input_arrow_type),\n                transform_type\n            )\n            .into()\n        }\n    );\n\n    let child = match children.remove(1) {\n        BoxedExpression::Sync(child) => child,\n        BoxedExpression::Async(_) => {\n            return Err(ExprError::Internal(anyhow!(\n                \"async child in iceberg_transform is not supported\"\n            )));\n        }\n    };\n    let transform = create_transform_function(&transform_type)\n        .map_err(|err| ExprError::Internal(err.into()))?;\n    Ok(IcebergTransform {\n        child,\n        transform,\n        input_arrow_type,\n        output_arrow_field,\n        return_type,\n    }\n    .boxed())\n}\n\n#[cfg(test)]\nmod test {","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/scalar/external/iceberg.rs#L143-L179","documentation":"iceberg_transform requires its value child expression to be a synchronous expression. If the second child is an async expression (BoxedExpression::Async), the builder refuses it because the transform is evaluated synchronously and cannot await.","triggerScenarios":"Building iceberg_transform(varchar, any) where children.remove(1) is an async expression — e.g. the input column expression is produced by an async lookup/UDF expression rather than a plain column reference.","commonSituations":"Composing iceberg_transform over the output of an async UDF or I/O-bound expression; planner rewrites that wrap the input in an async lookup expression.","solutions":["Materialize the async expression's result into a regular column/expression before applying iceberg_transform.","Restructure the plan so the transform input comes from a synchronous source (table column or computed expression).","If async input is genuinely required, extend iceberg_transform to support BoxedExpression::Async evaluation."],"exampleFix":"// before\nlet child = children.remove(1); // may be BoxedExpression::Async\n// after\nlet child = match children.remove(1) {\n    BoxedExpression::Sync(c) => c,\n    _ => return Err(/* materialize async input first */),\n};","handlingStrategy":"type-guard","validationCode":"if matches!(children[1], BoxedExpression::Async(_)) {\n    return Err(\"iceberg_transform input must be a sync expression\".into());\n}","typeGuard":"fn is_sync(e: &BoxedExpression) -> bool { matches!(e, BoxedExpression::Sync(_)) }","tryCatchPattern":null,"preventionTips":["Keep iceberg_transform inputs as plain column references or sync computed expressions.","Materialize async expression results into columns before applying partition transforms.","Review planner rules that may wrap transform inputs in async lookup expressions."],"tags":["iceberg","expression","async"],"backgroundTag":"unsupported-operation","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"}