{"record":{"id":"330aa13794ac4b27","repo":"can1357/oh-my-pi","slug":"pipeline-stages-must-be-callables","errorCode":null,"errorMessage":"pipeline() stages must be callables","messagePattern":"pipeline\\(\\) stages must be callables","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/eval/py/prelude.py","lineNumber":635,"sourceCode":"        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.\"\"\"\n        _emit_status(\"log\", message=str(message))\n        return None\n\n    def phase(title):\n        \"\"\"Record the current readable phase and emit a status ``phase`` event.\"\"\"\n        globals()[\"__omp_current_phase__\"] = str(title)\n        _emit_status(\"phase\", title=str(title))\n        return None\n\n    class _Budget:\n        \"\"\"Live view of the host Goal Mode token budget via the host bridge.\"\"\"\n\n        @property","sourceCodeStart":617,"sourceCodeEnd":653,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/eval/py/prelude.py#L617-L653","documentation":"pipeline() threads items through one-arg stage callables with a barrier between stages. It validates each stage argument is callable before use and raises TypeError otherwise. This catches bad stage lists up front rather than failing inside the pool.","triggerScenarios":"Calling pipeline(items, stage1, stage2) where a stage is not a callable — e.g. pipeline(rows, 'normalize', clean), passing a config object, or a value that is a method-call result instead of the method.","commonSituations":"Typing a stage name as a string instead of the function, forgetting to import the stage function, or passing a partially applied result that is data rather than a function.","solutions":["Pass function objects, not names: pipeline(items, normalize, clean) not pipeline(items, 'normalize', 'clean')","Verify each stage is imported and defined before the pipeline call","Wrap stages needing extra args: pipeline(items, lambda x: transform(x, opts))","Print/repr the stages list to find the non-callable entry"],"exampleFix":"// before\npipeline(rows, 'dedupe', enrich)\n// after\npipeline(rows, dedupe, enrich)","handlingStrategy":"validation","validationCode":"assert all(callable(s) for s in stages), \"pipeline stages must be callables\"","typeGuard":"def is_stage(s) -> bool:\n    return callable(s)","tryCatchPattern":"try:\n    out = pipeline(items, *stages)\nexcept TypeError as e:\n    if \"stages must be callables\" in str(e):\n        stages = [STAGE_REGISTRY[s] if isinstance(s, str) else s for s in stages]\n        out = pipeline(items, *stages)\n    else:\n        raise","preventionTips":["Keep a name->function registry if stages are configured by name","Validate stage lists at config load time","Don't confuse line-magic strings with functions"],"tags":["python","typeerror","pipeline"],"backgroundTag":"callable-type-check-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}