risingwavelabs/risingwave · error · Internal

async child in iceberg_transform is not supported

Error message

async child in iceberg_transform is not supported

What it means

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.

Solutions

  1. Materialize the async expression's result into a regular column/expression before applying iceberg_transform.
  2. Restructure the plan so the transform input comes from a synchronous source (table column or computed expression).
  3. If async input is genuinely required, extend iceberg_transform to support BoxedExpression::Async evaluation.

Example fix

// before
let child = children.remove(1); // may be BoxedExpression::Async
// after
let child = match children.remove(1) {
    BoxedExpression::Sync(c) => c,
    _ => return Err(/* materialize async input first */),
};
Defensive patterns

Strategy: type-guard

Validate before calling

if matches!(children[1], BoxedExpression::Async(_)) {
    return Err("iceberg_transform input must be a sync expression".into());
}

Type guard

fn is_sync(e: &BoxedExpression) -> bool { matches!(e, BoxedExpression::Sync(_)) }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/expr/impl/src/scalar/external/iceberg.rs:161

            (matches!(transform_type, Transform::Day) && matches!(actual_res_type, IcebergType::Primitive(PrimitiveType::Int))),
        ExprError::InvalidParam {
            name: "return type in iceberg_transform",
            reason: format!(
                "Expect return type {:?} but got {:?}, RisingWave return type is {:?}, input type is {:?}, transform type is {:?}",
                expect_res_type,
                actual_res_type,
                return_type,
                (input_type, input_arrow_type),
                transform_type
            )
            .into()
        }
    );

    let child = match children.remove(1) {
        BoxedExpression::Sync(child) => child,
        BoxedExpression::Async(_) => {
            return Err(ExprError::Internal(anyhow!(
                "async child in iceberg_transform is not supported"
            )));
        }
    };
    let transform = create_transform_function(&transform_type)
        .map_err(|err| ExprError::Internal(err.into()))?;
    Ok(IcebergTransform {
        child,
        transform,
        input_arrow_type,
        output_arrow_field,
        return_type,
    }
    .boxed())
}

#[cfg(test)]
mod test {

View on GitHub (pinned to 6469eb736d)