pathwaycom/pathway · error · ValueError
A batch UDF has to return a list but is annotated as returni
Error message
A batch UDF has to return a list but is annotated as returning {sig_return_type} What it means
ValueError raised when a batched UDF (max_batch_size set) relies on its signature for the return type, but the annotation is not a list. For batch mode each argument is a list and the function must return a list, so the signature must be annotated as list[T] (or List[T]); Pathway then unwraps T as the element type.
Source
Thrown at python/pathway/internals/udfs/__init__.py:206
wrapped_sig_return_type is None
or (
sig_return_type != Any
and not dt.dtype_issubclass(
wrapped_sig_return_type, dt.wrap(return_type)
)
)
):
warn(
f"The value of return_type parameter ({return_type}) is inconsistent with"
+ f" UDF's return type annotation ({sig_return_type}).",
stacklevel=3,
)
if return_type is ...: # return type only specified in signature
if self.max_batch_size is None:
return sig_return_type
else:
if not isinstance(wrapped_sig_return_type, dt.List):
raise ValueError(
f"A batch UDF has to return a list but is annotated as returning {sig_return_type}"
)
return wrapped_sig_return_type.wrapped
return return_type
def _wrap_function(self) -> Callable:
func = self.executor._wrap(self.__wrapped__)
if self.cache_strategy is not None:
func = with_cache_strategy(func, self.cache_strategy)
return func
def _prepare_executor(self, executor: Executor) -> Executor:
is_coroutine = inspect.iscoroutinefunction(self.__wrapped__)
if is_coroutine and isinstance(executor, SyncExecutor):
raise ValueError("The function is a coroutine. You can't use SyncExecutor.")
if isinstance(executor, AutoExecutor):
return async_executor() if is_coroutine else udfs.sync_executor()View on GitHub (pinned to fa2f74a464)
Solutions
- Annotate the batched UDF as returning list[ElementType], e.g. -> list[int]
- Alternatively pass return_type=int explicitly (return_type stays the element type even in batch mode)
- Ensure the function body actually builds and returns a list of the same length as the inputs
Example fix
// before
@pw.udf(max_batch_size=100)
def f(x: list[int]) -> int:
return [v * 2 for v in x]
// after
@pw.udf(max_batch_size=100)
def f(x: list[int]) -> list[int]:
return [v * 2 for v in x] Defensive patterns
Strategy: type-guard
Validate before calling
import inspect, typing
def batch_signature_ok(fn) -> bool:
sig = inspect.signature(fn)
rt = sig.return_annotation
origin = typing.get_origin(rt)
return origin in (list, typing.List) Type guard
import typing
def is_list_annotation(ann) -> bool:
return typing.get_origin(ann) in (list, typing.List) Prevention
- Annotate batched UDFs as -> list[ElementType]
- Keep the element type in return_type= and the full list type in the signature
- Add a unit test that constructs every UDF so annotation errors fail fast
When it happens
Trigger: @pw.udf(max_batch_size=...) def f(x: list[int]) -> int (annotated as returning int, not list[int]); any batched UDF whose -> annotation is a scalar type, Optional, or bare typing construct that does not resolve to dt.List.
Common situations: Developer converts a row-wise UDF to batch mode and forgets to change the return annotation from T to list[T]; mixing return_type parameter (which should stay T) with signature annotation conventions.
Related errors
- Batching is not supported for fully asynchronous UDFs.
- `{column_name}` should be a column definition, found {type(c
- type annotation of column `{column_name}` does not match col
- definitions of columns {names} lack type annotation
- Cannot perform {name} when column of type {dtypes_repr} is i
AI-assisted analysis of pathwaycom/pathway@fa2f74a464 (2026-08-15).
Data as JSON: /api/errors/011e7d6810409a73.
Report an issue: GitHub.