{"record":{"id":"8a5d81b4707d5650","repo":"FoundationAgents/OpenManus","slug":"command-cmd-timed-out-after-timeout-seconds","errorCode":null,"errorMessage":"Command '{cmd}' timed out after {timeout} seconds","messagePattern":"Command '(.+?)' timed out after (.+?) seconds","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"app/tool/file_operators.py","lineNumber":91,"sourceCode":"        process = await asyncio.create_subprocess_shell(\n            cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE\n        )\n\n        try:\n            stdout, stderr = await asyncio.wait_for(\n                process.communicate(), timeout=timeout\n            )\n            return (\n                process.returncode or 0,\n                stdout.decode(),\n                stderr.decode(),\n            )\n        except asyncio.TimeoutError as exc:\n            try:\n                process.kill()\n            except ProcessLookupError:\n                pass\n            raise TimeoutError(\n                f\"Command '{cmd}' timed out after {timeout} seconds\"\n            ) from exc\n\n\nclass SandboxFileOperator(FileOperator):\n    \"\"\"File operations implementation for sandbox environment.\"\"\"\n\n    def __init__(self):\n        self.sandbox_client = SANDBOX_CLIENT\n\n    async def _ensure_sandbox_initialized(self):\n        \"\"\"Ensure sandbox is initialized.\"\"\"\n        if not self.sandbox_client.sandbox:\n            await self.sandbox_client.create(config=SandboxSettings())\n\n    async def read_file(self, path: PathLike) -> str:\n        \"\"\"Read content from a file in sandbox.\"\"\"\n        await self._ensure_sandbox_initialized()","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/FoundationAgents/OpenManus/blob/52a13f2a57d8c7f6737eefb02ccf569594d44273/app/tool/file_operators.py#L73-L109","documentation":"LocalFileOperator.run_command runs a subprocess and bounds process.communicate() with asyncio.wait_for(timeout) (default 120s). On expiry it kills the process and raises TimeoutError naming the command and limit. Note the kill is best-effort (ProcessLookupError swallowed) — child processes of a shell=True command may survive the kill.","triggerScenarios":"Any command exceeding the timeout passed (or the 120s default): package installs, test suites, builds; commands started with shell=True that spawn children holding the pipes open, so even a 'finished' parent blocks communicate(); forgetting to pass timeout for a known-slow step.","commonSituations":"'npm install' / 'pip install' on cold caches; running a full test suite through the file operator; starting servers in the foreground; shell pipelines where a backgrounded child keeps stdout open.","solutions":["Pass an explicit, realistic timeout for slow steps: await op.run_command('npm ci', timeout=600).","Detached long-running processes: append 'nohup ... > /tmp/log 2>&1 &' so the shell returns instantly and the log is read separately.","For pipelines under shell=True, close inherited fds by redirecting every child: 'cmd > /tmp/out.log 2>&1 < /dev/null'.","Catch TimeoutError, then verify the process tree is actually dead (pkill -f pattern) before retrying, since kill() may miss grandchildren."],"exampleFix":"# before\nrc, out, err = await op.run_command(\"python -m http.server 8000\")  # never exits -> TimeoutError\n\n# after\nrc, out, err = await op.run_command(\n    \"nohup python -m http.server 8000 > /tmp/http.log 2>&1 < /dev/null &\"\n)\nrc, out, err = await op.run_command(\"sleep 1 && cat /tmp/http.log\")","handlingStrategy":"try-catch","validationCode":"rc, out, err = await op.run_command('test -d node_modules && echo yes || echo no')\nslow = ('install', 'build', 'test', 'pytest', 'compile')\ntimeout = 600 if any(s in cmd for s in slow) else 120\nrc, out, err = await op.run_command(cmd, timeout=timeout)","typeGuard":null,"tryCatchPattern":"try:\n    rc, out, err = await op.run_command(cmd, timeout=120)\nexcept TimeoutError:\n    await op.run_command('pkill -f \"<cmd-pattern>\" || true', timeout=10)  # kill survivors\n    rc, out, err = await op.run_command(cmd + ' > /tmp/cmd.log 2>&1 < /dev/null', timeout=600)","preventionTips":["Pass explicit timeouts matched to the command class.","Detach servers/daemons with nohup + redirects; read logs separately.","Redirect stdin/stdout of children so communicate() can finish.","After a timeout, clean the process tree before retrying — kill() may miss grandchildren."],"tags":["timeout","subprocess","shell","asyncio"],"backgroundTag":null,"analyzedSha":"52a13f2a57d8c7f6737eefb02ccf569594d44273","analyzedAt":"2026-08-15T02:33:49.993Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}