[BUG] Long-running Bash tool (900s timeout) completes but tool_result never delivered — conversation silently rewound via isMeta synthetic message

Resolved 💬 4 comments Opened Apr 7, 2026 by Konoyo-014 Closed May 23, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (closest: #39316, #44459 — different symptom/trigger)
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

A Bash tool call with timeout: 900000 ms (15 min) is issued and the command actually finishes within the timeout — but no tool_result is ever written to the session JSONL. When the user later types any message, the harness silently injects an isMeta: true synthetic user message whose parentUuid skips over the orphaned tool_use, effectively rewinding the conversation graph so the model never sees that the tool ran. From the user's perspective the assistant looks "interrupted" with no interrupt issued.

This is not the widespread 400 "tool use concurrency" error (#21321, #37452) — the session continues functioning normally. The orphan is silently dropped, the conversation stays healthy, but all the tool's work is invisible to the model.

What Should Happen?

When a Bash command finishes (or its timeout fires), a tool_result should always be written — stdout/stderr on success, a timeout/error sentinel otherwise. The model must be able to observe the outcome before processing the next user message.

Steps to Reproduce

  1. In an active session, call Bash with a long-running pipeline and timeout: 900000. In my case:

``
PROMPT_PATH=... && PATH=/opt/homebrew/bin:$PATH codex exec --sandbox danger-full-access ... 2>&1 | tee /tmp/output.log | tail -300
``

  1. Let the command run to completion without typing anything.
  2. After completion, type any new user message.

The orphaned tool_use receives no tool_result. The model has no record of the tool having run.

Evidence (session JSONL analysis)

Environment: Claude Code 2.1.87 · macOS Darwin 25.4.0 (arm64) · zsh · Opus 4.6 · Anthropic API

| Line | Timestamp (UTC) | Event |
|------|-----------------|-------|
| 888 | 06:30:40 | assistanttool_use Bash (mktemp) — returns normally on line 889 |
| 890 | 06:31:07 | assistanttool_use Bash toolu_01GXU9KWLHrayeVHCFK93McN (codex exec ...) — no matching tool_result anywhere in file |
| 892–893 | 07:03:15 | two queue-operation entries (32 min after line 890) |
| 894 | 07:03:15 | user isMeta: true · text: "Continue from where you left off." · parentUuid = line 889's UUID ← skips line 890 entirely |
| 895 | 07:03:15 | assistant text: "No response requested." |
| 896 | 07:03:15 | actual user message typed |

Programmatic check of the full session file:

total tool_uses:    341
total tool_results: 340
orphaned tool_uses: 1  →  toolu_01GXU9KWLHrayeVHCFK93McN  (Bash, line 890)

Proof the command actually finished:
The output file /tmp/codex-adversarial-review.log (105 KB) was last modified at 06:46 UTC — ~14m53s into the call, well within the 15-minute timeout. The process finished successfully; the failure is in the harness path that converts command completion into a tool_result.

Error Messages/Logs

No error is surfaced to the user. The session continues normally. The only observable symptoms are:

  1. The model responds to the post-interrupt message with "No response requested." (same symptom as #44459)
  2. The model then has no memory of the tool call or its output

Claude Code Version

2.1.87

Platform / OS / Terminal

  • Platform: Anthropic API
  • OS: macOS
  • Terminal: Claude Code desktop app (not a specific terminal emulator)

Additional Information

Why this differs from #39316 / #39602 / #21321:
Those issues involve orphaned pairs that trigger a 400 API error on the next turn. In this case the isMeta rewind cleanly severs the orphan from the conversation graph before any API call is made, so no 400 occurs — the session is structurally healthy but the tool's output is permanently lost to the model.

Why this differs from #44459:
That issue is about the model misinterpreting the "Continue from where you left off." message. The upstream problem here is that the message is being injected with a parentUuid that skips the orphaned tool_use — even a perfectly-interpreting model would have no idea the tool ran.

Workaround:
Issuing the same long-running Bash with run_in_background: true and reading output via BashOutput does not reproduce the issue — a re-run of the identical command using that path returned its tool_result correctly.

Suggested investigation areas:

  1. The foreground Bash timeout/exit handler — does it reliably emit a tool_result when timeout fires? Is there a code path that exits without writing one?
  2. The isMeta synthetic injection logic — should it validate that parentUuid is not skipping an unresolved tool_use? At minimum it should emit a synthetic error tool_result for any orphan before injecting the meta message.
  3. Whether piping through tee | tail affects the EOF-detection used to decide "command finished" — the process writes a 105 KB file but the harness may see a half-closed pipe.

This has reproduced across two separate sessions on the same machine (the user observed the identical behavior the previous night). Happy to share a sanitized JSONL excerpt if helpful.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗