risingwavelabs/risingwave · error
data type must be DataType::List
Error message
data type must be DataType::List
What it means
For functions returning `impl Iterator` with ListWrite output, the generated code needs the return type to be `DataType::List` to create an element array builder. If `return_type` is not a List, the generated code panics with `data type must be DataType::List` at runtime.
Source
Thrown at src/expr/macro/src/gen.rs:532
};
// the output expression in `eval_row`
let row_output = match user_fn.writer_type_kind {
Some(WriterTypeKind::FmtWrite) => quote! {{
let mut writer = String::new();
#output.map(|_| writer.into())
}},
Some(WriterTypeKind::IoWrite) => quote! {{
let mut writer = Vec::new();
#output.map(|_| writer.into())
}},
Some(WriterTypeKind::JsonbbBuilder) => quote! {{
let mut writer = jsonbb::Builder::<Vec<u8>>::new();
#output.map(|_| JsonbVal::from(writer.finish()).into())
}},
Some(WriterTypeKind::ListWrite) => quote! {{
let mut writer = {
let DataType::List(list_ty) = &self.context.return_type else {
panic!("data type must be DataType::List");
};
list_ty.elem().create_array_builder(1)
};
#output.map(|_| ListValue::new(writer.finish()).into())
}},
None if user_fn.core_return_type == "impl AsRef < [u8] >" => quote! {
#output.map(|s| s.as_ref().into())
},
None => quote! {{
let output #annotation = #output;
output.map(|s| s.into())
}},
};
// the main body in `eval`
let eval = if let Some(batch_fn) = &self.batch_fn {
assert!(
!variadic,
"customized batch function is not supported for variadic functions"View on GitHub (pinned to 6469eb736d)
Solutions
- Fix the type_infer function to always return DataType::List for this function
- Fix the frontend inference so the return type is a List
- Guard the generated code with a clear error instead of panic if the type can vary
Example fix
// before type_infer = "|_| Ok(DataType::Varchar)" // after type_infer = "|_| Ok(DataType::List(Box::new(DataType::Varchar.into())))"
Defensive patterns
Strategy: validation
Validate before calling
fn ensure_list_return(rt: &DataType) -> Result<(), String> {
match rt { DataType::List(_) => Ok(()), other => Err(format!("return type must be List, got {other:?}")) }
} Type guard
fn as_list_type(rt: &DataType) -> Option<&ListType> { match rt { DataType::List(l) => Some(l), _ => None } } Try / catch
match as_list_type(&func.return_type()) {
None => return Err("function must return a list".into()),
Some(list_ty) => run_list_write_udf(list_ty),
} Prevention
- Ensure type_infer returns DataType::List for ListWrite functions
- Add a unit test asserting the inferred return type is a list
- Document writer-kind requirements in the function declaration
When it happens
Trigger: A scalar function declared with `#[return_type = "list"]`/ListWrite writer whose actual inferred return type is not a List — e.g. type inference returns a scalar or struct type for a function generating list output.
Common situations: Custom type_infer returning the wrong type for a list-producing function; frontend infers a non-list return for a UDF that uses the ListWrite writer path.
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
- type inference for this function should be specially handled
- type inference function cannot be automatically derived. You
- You can't use the macro on this type
- Expected #[serde_prefix_all(skip)]
- Must have no buffer in a list array
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/b2d44fb52ea5d29d.
Report an issue: GitHub.