{"record":{"id":"37c40253d61d80ed","repo":"JuliusBrussee/caveman","slug":"caveman-code-host-command-shell-is-not-available","errorCode":null,"errorMessage":"caveman-code: host command shell is not available","messagePattern":"caveman-code: host command shell is not available","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/code.ts","lineNumber":316,"sourceCode":"      `Times out after ${BASH_TIMEOUT_MS} ms; output is capped at ${caps.bash} bytes.`,\n    input: schema.object({\n      command: schema.string(),\n      timeoutMs: schema.optional(schema.integer()),\n    }),\n    effect: \"external\",\n    result: \"inline\",\n    timeoutMs: BASH_TIMEOUT_MS,\n    async execute(input, signal) {\n      const timeoutMs = Math.min(input.timeoutMs ?? BASH_TIMEOUT_MS, BASH_TIMEOUT_MS);\n      const shell = hostShellInvocation(input.command, process.platform, buildCodingProcessEnv());\n      const run = await runProcess(\n        shell.command,\n        shell.args,\n        await workspaceRoot(),\n        timeoutMs,\n        signal,\n      );\n      if (run.spawnFailed) throw new Error(\"caveman-code: host command shell is not available\");\n      const body = [\n        `exit ${run.timedOut ? `timeout after ${timeoutMs}ms` : run.code}`,\n        run.output.trim() === \"\" ? \"(no output)\" : run.output,\n      ].join(\"\\n\");\n      const text = capOutput(body, caps.bash);\n      record(`bash:${input.command.slice(0, 60)}`, text);\n      return text;\n    },\n  });\n\n  const editTool = tool({\n    name: \"edit_file\",\n    description:\n      \"Replace an exact string in a workspace file. The old string must appear exactly \" +\n      \"once unless replace_all is set. Writes to disk.\",\n    input: schema.object({\n      path: schema.string(),\n      old_string: schema.string(),","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/code.ts#L298-L334","documentation":"The bash tool spawns the host shell produced by `hostShellInvocation` (platform-dependent /bin/bash or sh). If that shell binary cannot be spawned at all (ENOENT/EPERM), the run is marked spawnFailed and this error is thrown. It is an environment capability failure, not a failure of the command itself.","triggerScenarios":"Invoking the `bash` tool on a host without a usable shell binary: Windows without bash (only cmd/powershell exist), containers with no shell, or environments where buildCodingProcessEnv() strips PATH entries containing the shell, or execute permissions deny spawning it.","commonSituations":"Windows deployments (no /bin/bash); minimal/distroless containers; macOS sandbox-exec profiles blocking /bin/sh; a PATH env var overwritten to a directory set that excludes /bin and /usr/bin.","solutions":["Ensure a POSIX shell (bash or sh) exists and is executable in the agent's runtime environment; on Windows install Git Bash or WSL and make it reachable","Check that the process env passed to the agent does not clobber PATH — buildCodingProcessEnv may sanitize it, so keep the shell's directory on the sanitized PATH","If the host genuinely has no shell, route work to the other tools (edit_file, grep) instead of bash, or run the agent in a proper container","Verify spawn capability directly: `node -e \"require('child_process').spawnSync(process.platform==='win32'?'bash':'/bin/sh',['-c','echo ok'])\"` in the same environment"],"exampleFix":"// before: PATH sanitized to empty, shell unresolvable\nenv: { PATH: \"\" }\n\n// after: keep system dirs on PATH so hostShellInvocation can spawn\nenv: { PATH: \"/usr/local/bin:/usr/bin:/bin\" }","handlingStrategy":"validation","validationCode":"import { spawnSync } from \"node:child_process\";\n\nfunction shellAvailable(): boolean {\n  const shell = process.platform === \"win32\" ? \"bash\" : \"/bin/sh\";\n  return spawnSync(shell, [\"-c\", \"true\"]).error === undefined;\n}\n\nif (!shellAvailable()) throw new Error(\"no host shell; bash tool disabled\");","typeGuard":null,"tryCatchPattern":"try {\n  const res = await bashTool.execute({ command }, signal);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"host command shell is not available\")) {\n    // do not retry the command; fix the environment instead\n    throw new Error(`shell missing on host (${process.platform}); install bash/sh`);\n  }\n  throw err;\n}","preventionTips":["On Windows, install Git Bash or run under WSL and verify bash resolves on PATH","Keep /bin and /usr/bin on the PATH your process env builder produces","Prefer the dedicated read/edit/grep tools for file work so a missing shell degrades gracefully"],"tags":["environment","shell","spawn-failure","platform"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}