{"record":{"id":"ebf590d24842c5d5","repo":"risingwavelabs/risingwave","slug":"udf-returned-at-column-1-but-expected","errorCode":null,"errorMessage":"UDF returned {:?} at column 1, but expected {:?}","messagePattern":"UDF returned (.+?) at column 1, but expected (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/core/src/table_function/user_defined.rs","lineNumber":113,"sourceCode":"                output.columns().len()\n            );\n        }\n        if output.column_at(0).data_type() != DataType::Int32 {\n            bail!(\n                \"UDF returned {:?} at column 0, but expected {:?}\",\n                output.column_at(0).data_type(),\n                DataType::Int32,\n            );\n        }\n        if output.column_at(0).as_int32().raw_iter().any(|i| i < 0) {\n            bail!(\"UDF returned negative row index\");\n        }\n        if !output\n            .column_at(1)\n            .data_type()\n            .equals_datatype(&self.return_type)\n        {\n            bail!(\n                \"UDF returned {:?} at column 1, but expected {:?}\",\n                output.column_at(1).data_type(),\n                &self.return_type,\n            );\n        }\n        Ok(())\n    }\n}\n\npub fn new_user_defined(prost: &PbTableFunction, chunk_size: usize) -> Result<BoxedTableFunction> {\n    let udf = prost.get_udf()?;\n\n    let arg_types = udf.arg_types.iter().map(|t| t.into()).collect::<Vec<_>>();\n    let return_type = DataType::from(prost.get_return_type()?);\n\n    let language = udf.language.as_str();\n    let runtime = udf.runtime.as_deref();\n    let link = udf.link.as_deref();","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/core/src/table_function/user_defined.rs#L95-L131","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (Python UDF declared INT but returns int64)\nreturn pa.record_batch([indices, pa.array(values)], names=[\"i\", \"v\"])\n// after\nreturn pa.record_batch([indices, pa.array(values, pa.int32())], names=[\"i\", \"v\"])","handlingStrategy":"validation","validationCode":"# Python UDF: cast value column to declared type\nvalues = pa.array(raw_values, type=pa.types_for(declared_return_type))","typeGuard":null,"tryCatchPattern":"match chunk_result {\n    Ok(c) => c,\n    Err(e) if e.to_string().contains(\"at column 1, but expected\") => {\n        bail!(\"UDF value column type mismatches declared return type\");\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["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"],"tags":["udf","table-function","type-mismatch","arrow"],"backgroundTag":"type-mismatch","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"}