risingwavelabs/risingwave · error
UDF returned at column 0, but expected
Error message
UDF returned {:?} at column 0, but expected {:?} What it means
Guard in check_output for table-function UDFs: the UDF's output column 0 (the index column) has a type other than the required Int32. The generic generator protocol mandates an i32 index as column 0; a wrongly declared UDF return type triggers this error during evaluation.
Solutions
- Change the UDF to emit the row-index column as Arrow Int32 (e.g. cast to `pa.int32()` in pyarrow).
- If the UDF cannot change, cast the index column in the UDF wrapper/service before returning the batch.
- Update any SDK examples/docs where the index was produced as Int64.
Example fix
// before (Python) return pa.record_batch([pa.array(range(n)), values], names=["i", "v"]) # i is int64 // after return pa.record_batch([pa.array(range(n), pa.int32()), values], names=["i", "v"])
Defensive patterns
Strategy: validation
Validate before calling
# Python UDF: force index column to int32 before returning indices = pa.array(range(n), type=pa.int32())
Try / catch
match chunk_result {
Ok(c) => c,
Err(e) if e.to_string().contains("at column 0, but expected") => {
bail!("UDF index column must be Arrow Int32; fix UDF return types");
}
Err(e) => return Err(e.into()),
} Prevention
- Always construct the index column with an explicit pa.int32() type in Python UDFs
- Remember Python ints become int64 by default in pyarrow — cast explicitly
- Document the required output schema in the UDF template/SDK
When it happens
Trigger: The UDF returns a two-column batch but column 0 is Int64/UInt32/Utf8 etc., so `output.column_at(0).data_type() != DataType::Int32` holds.
Common situations: A Python UDF emits 64-bit integers (Python ints default to int64 in pyarrow); a generated index column typed as Int64 in the UDF implementation.
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 1, 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/9e01978213d5c533.
Report an issue: GitHub.
Appendix: source
Thrown at src/expr/core/src/table_function/user_defined.rs:99
let output = DataChunk::new(
vec![origin_indices.into_ref(), output.column_at(1).clone()],
output.visibility().clone(),
);
yield output;
}
}
/// Check if the output chunk is valid.
fn check_output(&self, output: &DataChunk) -> Result<()> {
if output.columns().len() != 2 {
bail!(
"UDF returned {} columns, but expected 2",
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,
);View on GitHub (pinned to 6469eb736d)