{"record":{"id":"c9409f8162a61e37","repo":"can1357/oh-my-pi","slug":"parallel-expects-an-iterable-of-zero-arg-callabl","errorCode":null,"errorMessage":"parallel() expects an iterable of zero-arg callables","messagePattern":"parallel\\(\\) expects an iterable of zero-arg callables","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/eval/py/prelude.py","lineNumber":622,"sourceCode":"                i = futures[fut]\n                try:\n                    results[i] = fut.result()\n                except BaseException as exc:  # noqa: BLE001 - propagate to caller\n                    errors[i] = exc\n        if errors:\n            raise errors[min(errors)]\n        return results\n\n    def parallel(thunks):\n        \"\"\"Run zero-arg callables through a bounded pool, preserving input order.\n\n        Barriers until all finish; re-raises the lowest-index exception if any\n        thunk raised. Pool width tracks the task tool's ``task.maxConcurrency``.\n        \"\"\"\n        thunks = list(thunks)\n        for t in thunks:\n            if not callable(t):\n                raise TypeError(\"parallel() expects an iterable of zero-arg callables\")\n        return _pool_map(thunks, lambda t: t())\n\n    def pipeline(items, *stages):\n        \"\"\"Map items left-to-right through one-arg stage callables.\n\n        Every item clears stage N before any item enters stage N+1 (barrier per\n        stage). Stage 1 receives the original item; later stages receive the\n        previous stage's result. Pool width tracks ``task.maxConcurrency``.\n        \"\"\"\n        current = _AwaitableList(items)\n        for stage in stages:\n            if not callable(stage):\n                raise TypeError(\"pipeline() stages must be callables\")\n            current = _pool_map(current, stage)\n        return current\n\n    def log(message):\n        \"\"\"Emit a status ``log`` event for TUI rendering.\"\"\"","sourceCodeStart":604,"sourceCodeEnd":640,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/eval/py/prelude.py#L604-L640","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nparallel([fetch(url) for url in urls])\n// after\nparallel([lambda u=url: fetch(u) for u in urls])","handlingStrategy":"validation","validationCode":"if (not isinstance(thunks, (list, tuple)) or any(not callable(t) for t in thunks)):\n    raise TypeError(\"parallel() requires zero-arg callables\")","typeGuard":"def is_zero_arg_callable(t) -> bool:\n    return callable(t) and not isinstance(t, type)","tryCatchPattern":"try:\n    results = parallel(thunks)\nexcept TypeError as e:\n    if \"zero-arg callables\" in str(e):\n        thunks = [t if callable(t) else (lambda t=t: t) for t in thunks]\n        results = parallel(thunks)\n    else:\n        raise","preventionTips":["Never pre-call thunks; pass function references","Use functools.partial or lambda to bind args","Assert callable on list items in tests"],"tags":["python","typeerror","concurrency"],"backgroundTag":"callable-type-check-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}