{"record":{"id":"08ea1cc8f4d5a342","repo":"shareAI-lab/learn-claude-code","slug":"only-bash-commands-can-run-in-the-background","errorCode":null,"errorMessage":"Only Bash commands can run in the background","messagePattern":"Only Bash commands can run in the background","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"s11_background_tasks/code.py","lineNumber":316,"sourceCode":"        output = handler(**block.input) if handler else f\"Unknown: {block.name}\"\n    except Exception as error:\n        output = f\"Error: {error}\"\n    return str(output)\n\n\n# -- New in s11: background execution --\n\nclass BackgroundManager:\n    def __init__(self):\n        self.tasks: dict[str, dict] = {}\n        self.results: dict[str, str] = {}\n        self._ready: list[str] = []\n        self._counter = 0\n        self._lock = threading.Lock()\n\n    def start(self, block) -> str:\n        if block.name != \"bash\":\n            raise ValueError(\"Only Bash commands can run in the background\")\n        command = block.input.get(\"command\")\n        if not isinstance(command, str) or not command.strip():\n            raise ValueError(\"Bash command cannot be empty\")\n\n        with self._lock:\n            self._counter += 1\n            task_id = f\"bg_{self._counter:04d}\"\n            self.tasks[task_id] = {\n                \"tool_use_id\": block.id,\n                \"command\": command,\n                \"status\": \"running\",\n            }\n\n        thread = threading.Thread(\n            target=self._run,\n            args=(task_id, command),\n            daemon=True,\n        )","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/shareAI-lab/learn-claude-code/blob/985456f4adea6f4df8fbad4112245dbd97444eae/s11_background_tasks/code.py#L298-L334","documentation":"Raised by BackgroundManager.start() in s11_background_tasks/code.py:316 when asked to run a tool block whose name is not 'bash'. Background execution in s11 is implemented by shelling out the command in a worker thread, so only Bash command blocks — which carry a 'command' string to execute — are supported. The check is an exact string comparison on block.name before any input validation.","triggerScenarios":"Passing a tool-call block whose .name is 'read', 'edit', 'write', 'grep', or any non-'bash' tool to BackgroundManager.start(); routing agent tool_use blocks to the background manager without filtering by name; constructing a synthetic block dict/object with the wrong name casing ('Bash').","commonSituations":"A dispatcher that forwards all tool calls to the background manager for uniformity; agent code that decides to 'run this in the background' for an edit or read operation; refactors that rename the bash tool constant without updating this comparison.","solutions":["Only call start() with blocks whose name is exactly 'bash'; gate the call with `if block.name == 'bash':`.","For non-bash tools, execute them synchronously through their normal handler instead of the background manager.","If you added a new shell-like tool, extend the check to accept it explicitly rather than bypassing it."],"exampleFix":"# before\nbg_id = background.start(block)  # any tool block\n\n# after\nif block.name == 'bash':\n    bg_id = background.start(block)\nelse:\n    result = run_tool_sync(block)","handlingStrategy":"type-guard","validationCode":"def block_is_backgroundable(block) -> bool:\n    return getattr(block, 'name', None) == 'bash'","typeGuard":"def is_bash_block(block) -> bool:\n    return getattr(block, 'name', '') == 'bash'","tryCatchPattern":"try:\n    bg_id = background.start(block)\nexcept ValueError as e:\n    if 'Only Bash' in str(e):\n        result = run_tool_sync(block)  # fall back to synchronous execution\n    else:\n        raise","preventionTips":["Filter tool blocks by name before deciding background vs. synchronous.","Keep the tool-name constant shared between the dispatcher and the background manager.","If you add shell-like tools, whitelist them explicitly rather than catching the error."],"tags":["background-tasks","tools","validation"],"backgroundTag":null,"analyzedSha":"985456f4adea6f4df8fbad4112245dbd97444eae","analyzedAt":"2026-08-14T22:02:26.028Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}