risingwavelabs/risingwave · error

UDF returned at column 1, but expected

Error message

UDF returned {:?} at column 1, but expected {:?}

What it means

`check_output` requires column 1 (the value column) of the table function output to exactly match the expression's declared `return_type`. A mismatch between the returned Arrow-derived type and the catalog return type fails with this error.

Solutions

  1. Align the UDF's returned column type with the return type declared in `CREATE FUNCTION` / the UDF descriptor.
  2. Explicitly cast the value column in the UDF (or UDF service wrapper) to the declared Arrow type.
  3. If the declared type is wrong, re-register the function with the correct return type.

Example fix

// before (Python UDF declared INT but returns int64)
return pa.record_batch([indices, pa.array(values)], names=["i", "v"])
// after
return pa.record_batch([indices, pa.array(values, pa.int32())], names=["i", "v"])
Defensive patterns

Strategy: validation

Validate before calling

# Python UDF: cast value column to declared type
values = pa.array(raw_values, type=pa.types_for(declared_return_type))

Try / catch

match chunk_result {
    Ok(c) => c,
    Err(e) if e.to_string().contains("at column 1, but expected") => {
        bail!("UDF value column type mismatches declared return type");
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: The UDF returns two columns with a valid Int32 index, but column 1's `DataType` does not `equals_datatype` the `self.return_type` declared at UDF registration — e.g. Utf8 vs LargeUtf8, Int64 vs Int32, nullable differences handled as distinct types.

Common situations: The UDF service returns int64 while the function was declared `INT`; JSON/struct types serialized differently than declared; timezone or precision differences in timestamp columns.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/expr/core/src/table_function/user_defined.rs:113

                output.columns().len()
            );
        }
        if output.column_at(0).data_type() != DataType::Int32 {
            bail!(
                "UDF returned {:?} at column 0, but expected {:?}",
                output.column_at(0).data_type(),
                DataType::Int32,
            );
        }
        if output.column_at(0).as_int32().raw_iter().any(|i| i < 0) {
            bail!("UDF returned negative row index");
        }
        if !output
            .column_at(1)
            .data_type()
            .equals_datatype(&self.return_type)
        {
            bail!(
                "UDF returned {:?} at column 1, but expected {:?}",
                output.column_at(1).data_type(),
                &self.return_type,
            );
        }
        Ok(())
    }
}

pub fn new_user_defined(prost: &PbTableFunction, chunk_size: usize) -> Result<BoxedTableFunction> {
    let udf = prost.get_udf()?;

    let arg_types = udf.arg_types.iter().map(|t| t.into()).collect::<Vec<_>>();
    let return_type = DataType::from(prost.get_return_type()?);

    let language = udf.language.as_str();
    let runtime = udf.runtime.as_deref();
    let link = udf.link.as_deref();

View on GitHub (pinned to 6469eb736d)