can1357/oh-my-pi · error · TypeError
parallel() expects an iterable of zero-arg callables
Error message
parallel() expects an iterable of zero-arg callables
What it means
parallel() in the eval Python prelude runs zero-arg thunks concurrently via a shared pool that tracks task.maxConcurrency. Before scheduling, it validates that every item in the iterable is callable and raises TypeError immediately if any is not. This fail-fast check prevents a confusing mid-pool failure when a non-callable is invoked.
Source
Thrown at packages/coding-agent/src/eval/py/prelude.py:622
i = futures[fut]
try:
results[i] = fut.result()
except BaseException as exc: # noqa: BLE001 - propagate to caller
errors[i] = exc
if errors:
raise errors[min(errors)]
return results
def parallel(thunks):
"""Run zero-arg callables through a bounded pool, preserving input order.
Barriers until all finish; re-raises the lowest-index exception if any
thunk raised. Pool width tracks the task tool's ``task.maxConcurrency``.
"""
thunks = list(thunks)
for t in thunks:
if not callable(t):
raise TypeError("parallel() expects an iterable of zero-arg callables")
return _pool_map(thunks, lambda t: t())
def pipeline(items, *stages):
"""Map items left-to-right through one-arg stage callables.
Every item clears stage N before any item enters stage N+1 (barrier per
stage). Stage 1 receives the original item; later stages receive the
previous stage's result. Pool width tracks ``task.maxConcurrency``.
"""
current = _AwaitableList(items)
for stage in stages:
if not callable(stage):
raise TypeError("pipeline() stages must be callables")
current = _pool_map(current, stage)
return current
def log(message):
"""Emit a status ``log`` event for TUI rendering."""View on GitHub (pinned to 9690622007)
Solutions
- Wrap argument-taking functions in lambdas or functools.partial: parallel([lambda: f(x) for x in xs])
- Check for accidental double-invocation — pass the function itself, not f() or await f()
- Filter or fix None values in the input list before calling parallel()
- Ensure every element is a zero-arg callable: parallel accepts thunks, not values or coroutines
Example fix
// before parallel([fetch(url) for url in urls]) // after parallel([lambda u=url: fetch(u) for u in urls])
Defensive patterns
Strategy: validation
Validate before calling
if (not isinstance(thunks, (list, tuple)) or any(not callable(t) for t in thunks)):
raise TypeError("parallel() requires zero-arg callables") Type guard
def is_zero_arg_callable(t) -> bool:
return callable(t) and not isinstance(t, type) Try / catch
try:
results = parallel(thunks)
except TypeError as e:
if "zero-arg callables" in str(e):
thunks = [t if callable(t) else (lambda t=t: t) for t in thunks]
results = parallel(thunks)
else:
raise Prevention
- Never pre-call thunks; pass function references
- Use functools.partial or lambda to bind args
- Assert callable on list items in tests
When it happens
Trigger: Calling parallel() with an iterable containing anything not callable — e.g. parallel([fetch_data, None]), parallel(['task1', 'task2']), or passing coroutine objects / results of calling functions instead of functions.
Common situations: Passing partial results instead of thunks, mapping a list comprehension that already called the functions, forgetting a lambda wrapper around an argument-taking function, or a variable holding None due to an earlier failed lookup.
Related errors
- tool.{self._name}(...) expects a dict of arguments (got {typ
- pipeline() stages must be callables
- display(..., raw=True) requires a MIME bundle dict
- native spelling thread stopped
- Agent is already processing. Use steer() or followUp() to qu
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c9409f8162a61e37.
Report an issue: GitHub.