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
- Align the UDF's returned column type with the return type declared in `CREATE FUNCTION` / the UDF descriptor.
- Explicitly cast the value column in the UDF (or UDF service wrapper) to the declared Arrow type.
- 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
- Keep the UDF's declared return type (CREATE FUNCTION) and its actual Arrow output in sync
- Cast the value column explicitly rather than relying on type inference
- Re-check the declared type whenever the UDF implementation changes
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
- UDF returned at column 0, but expected
- UDF returned a value of type
- UDF returned , but expected
- UDF returned columns, but expected 2
- UDF returned negative row index
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)