[Bug] Claude still wraps commands in unavailable `timeout`/`gtimeout` on macOS instead of using built-in bash-timeout (re-file of locked #3361 / #10600)

Status Fixed / completed
Reported on v2.1.214
Maintainer reply None cached
Activity 1 comment · opened Jul 19, 2026 · closed Jul 19, 2026

Re-filing #3361 and #10600 — both were auto-closed (NOT_PLANNED by stale-bot, duplicate respectively) and locked, with no fix and no maintainer response. The bot in #3361 explicitly says: "If you're experiencing a similar issue, please open a new issue." This is that new issue.

Pinging the original reporters so context isn't lost: @lukehutch (#3361), @Geenz (#10600).

---

Summary

On macOS (where GNU timeout/gtimeout are not installed by default), Claude Code repeatedly wraps shell commands in timeout N <cmd> / gtimeout N <cmd>. The command fails with command not found: timeout, the model burns tokens reacting to it, and in a non-trivial fraction of cases hallucinates success on the empty output. Claude Code has a built-in bash-timeout (BASH_DEFAULT_TIMEOUT_MS / BASH_MAX_TIMEOUT_MS), but the model does not reach for it — it treats the external timeout utility as the only lever.

Environment

  • Claude Code 2.1.214
  • Darwin 25.5.0 arm64 (macOS), zsh
  • timeout/gtimeout not present; coreutils not installed via brew

Reproduction

Any long-running or network-shaped task tends to trigger it. The model emits commands like:

timeout 300 <long-running-command> 2>&1 | tail -30

Result:

(eval):1: command not found: timeout

Evidence from real transcripts

Mining Claude Code session transcripts to quantify this, across the corpus:

  • 71 Bash invocations were wrapped in an external timeout N/gtimeout N prefix.
  • The error command not found: timeout appears ~441 times in tool results — the real scale of the harm.
  • 104 --timeout=/--timeout N invocations (legitimate pytest/tool flags) were correctly used — so the model knows the concept of a timeout; the failure is specifically the external command.

The harness itself signals the built-in timeout to the model (Command timed out after 2m 0s appears in 68 session files), yet the model's reaction is to prepend an external timeout to the next command rather than reason about BASH_MAX_TIMEOUT_MS.

Why it happens (classified from 31 contextual cases)

The model does not distinguish between Claude Code's built-in bash-timeout and the GNU timeout utility. In its world:

  • the 2-minute harness limit is a fixed property of the environment;
  • timeout N is a separate utility to "give a command less time" or "kill a hung process".

The link "I want >2 min → raise BASH_MAX_TIMEOUT_MS" is never made — even though that env var is surfaced in the Claude Code changelog the model sees at session start. The model's justifications fall into three buckets:
| Intent | Share | Example (verbatim, anonymized) |
|---|---|---|
| (a) Fears a hang (pytest deadlock / input() / network CLI) | ~55% | "…the process seems to have hung. I'll run it in the foreground with a timeout to see the real result." |
| (b) Knows the 2-min harness ceiling, wants more | ~13% | "The command hung and exceeded the 2-minute timeout." → next command wrapped in timeout 20 |
| (c) Ritual / no stated reason | ~32% | wraps long-running pipeline commands in timeout 300 by habit |

Reaction to command not found: timeout (across cases)

  • ~50% — model notices and substitutes (re-run without prefix, switch to pytest --timeout=N, or a different tool).
  • ~20% — model ignores the error and reasons about the code as if the command had run; observed a hallucination "all 22 tests are green" on a command that never executed. This is the most harmful mode.
  • Token-burn diagnostic loops are rare because the error is unambiguous — the harm is mostly the silent-success hallucinations and the friction.

Suggested fix (any of)

  • Treat timeout/gtimeout as an unavailable command in the model's environment knowledge on macOS, and either (a) auto-strip the prefix and rely on the built-in timeout, or (b) surface a hint to use BASH_DEFAULT_TIMEOUT_MS/BASH_MAX_TIMEOUT_MS when the model's stated goal is "give the command more than 2 minutes".
  • At minimum, when a Bash command returns command not found: timeout, do not let the model interpret empty output as success.

Related

  • #3361 (locked) — original; closed NOT_PLANNED by stale-bot.
  • #10600 (locked) — closed as duplicate of #3361.
  • #76082 (open) — separate but related: normalizeToolInput silently corrupts bash commands, relevant if a hook-based rewrite approach is considered.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗