Skip to content

[BUG] Turn goes permanently idle (event loop idle in kevent64, no error): dropped tool_result, stalled compaction, or queued input never taken up (macOS, 2.1.268 to 2.1.283) #94252

Description

@SnoElement

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code (2.1.270, matches current npm latest)

Related but not identical, cross-referenced deliberately: #91648 (same defect shape on Windows/Bash), #83848 (subagent transcripts stopping after a tool_use with no tool_result), #92789 (idle-not-crashed session hang on Linux desktop). I believe these share a root cause. What I add here is sample evidence showing the event loop is idle with nothing registered, plus a case where a parent and its in-process teammate wedged independently in the same OS process.

What's Wrong?

A Read tool call's tool_result is never delivered. The turn's continuation never settles, and the process goes fully idle rather than erroring or timing out. The elapsed-time counter keeps incrementing, so it is indistinguishable from slowness.

This happened twice within one OS process: first in a background in-process teammate, then in the parent session 4.5 minutes later.

The process is idle, not deadlocked and not spinning. sample of the wedged process, taken twice ~5 minutes apart, identical in shape both times:

3213 Thread_32466316   DispatchQueue_1: com.apple.main-thread  (serial)
  ! :  3148 kevent64  (in libsystem_kernel.dylib) + 8

3148 of 3213 samples on the main thread are in kevent64, the idle event-loop wait. Every Bun Pool worker thread is parked in __ulock_wait2. CPU steady at ~1%. No thread is blocked in a file or socket syscall and no mutex is contended on the main thread. Nothing is registered that could ever wake the turn, which is why waiting cannot recover it.

No API request is in flight. lsof -nP -i -a -p <pid> shows zero sockets in ESTABLISHED.

Exactly one orphaned tool_use per agent. Counting tool_use ids against tool_result ids in the transcripts:

Agent tool_use tool_result orphaned
Parent session 71 70 1
In-process teammate 8 7 1

Both orphans are Read, both targeting small local files on APFS:

parent    2026-09-14T09:31:30.991Z  Read  <26,618-byte local .md>
teammate  2026-09-14T09:26:58.200Z  Read  <27,445-byte local .md>

isApiErrorMessage entries in either transcript: 0.

Out-of-order completion in the teammate. It emitted two Read calls in one assistant message, 203ms apart. The second returned in 15ms; the first never returned:

09:26:58.200  assistant  tool_use:Read(ORPHAN)    <- never returns
09:26:58.403  assistant  tool_use:Read(SIBLING)
09:26:58.418  user       tool_result(SIBLING)     <- returns in 15ms

That is the signature of a lost result in parallel tool-call fan-in.

Teammate metadata (from the subagent .meta.json):

{"taskKind": "in_process_teammate", "requestShape": "background",
 "requestNonInteractive": true, "permissionMode": "auto", "spawnDepth": 0}

The teammate wedged first; the parent wedged on its next tool call 4.5 minutes later. Since an in-process teammate shares the parent's event loop, a dropped continuation in one branch appears able to strand the other.

What Should Happen?

A tool_use with no tool_result should hit a timeout and surface a tool error, letting the turn continue or fail visibly. It should never leave the session in a state where the event loop is idle with no pending work and no path to recovery.

Error Messages/Logs

There are none, and that is the core of the report. No error in the UI, no error in the transcript, no timeout, no retry. The only way to distinguish this from ordinary slowness is to sample the process and notice the main thread is in the idle kevent64 wait with nothing registered.

Secondary symptom: pressing Esc returns to the prompt, but subsequent prompts also produce no output, which suggests the agent loop's state does not fully reset after the cancel.

Steps to Reproduce

I do not have a deterministic repro, so I am reporting the conditions and the measurement method instead.

Conditions present in both occurrences:

  1. A long-running interactive session (~127.7k tokens of context at the time of the hang).
  2. One background in-process teammate spawned via the Agent tool, running concurrently in the same OS process.
  3. A Read on a small local file, dispatched while that teammate was live.

To detect it rather than guess at it:

  1. sample <pid> 5 on the apparently-stuck process. If the main thread is in kevent64 and the worker threads are in __ulock_wait2, it is idle, not busy.
  2. lsof -nP -i -a -p <pid> and confirm zero ESTABLISHED sockets, so no request is in flight.
  3. In the session .jsonl, collect every tool_use id and every tool_result tool_use_id and diff them. The orphan is the dropped call.

Claude Model

claude-opus-5 (parent), claude-sonnet-5 (in-process teammate)

Is this a regression?

I don't know

Last Working Version

(not known)

Claude Code Version

2.1.270 (Claude Code)

Platform

AWS Bedrock

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

macOS 27.0 (build 26A428), Darwin 27.0.0, xnu-13432.1.9, arm64 (T6041). Runtime is Bun; worker threads appear as Bun Pool N.

Ruled out by testing, please do not treat these as the cause:

  • File or filesystem. Both target files read instantly from another session afterward. Local APFS, not a File Provider or network mount. No stuck fileproviderctl, no processes in U state.
  • File size. In the same session a 356,726-byte PDF and a 315,945-byte PDF read successfully, and a 25,777-byte markdown read successfully twice. The orphans were 26,618 and 27,445 bytes. No size threshold.
  • Permissions. An allow rule covered both paths and auto mode was on. 70 of 71 calls in the same session succeeded, including a read in the same directory as the teammate's orphan.
  • Host resource exhaustion. 63% memory free, 2.31MB of 1024MB swap used, 1303 of 8000 processes for the uid.
  • Hung hook or child process. The only children were caffeinate and two idle MCP servers.
  • Socket state. The three CLOSED FDs are ordinary HTTP-pool residue; healthy sessions on the same machine had 14 and 5.

Suggested fix direction: a watchdog on pending tool_use ids. If a tool_use has no tool_result after N seconds and the event loop has nothing pending, surface a tool error instead of waiting forever. That alone converts a silent unrecoverable hang into a recoverable error, independent of whatever drops the result.

Update (after two further failure modes were found): this fix direction is too narrow. Two other paths reach the same idle event loop with no pending tool_use at all -- #94261 (compaction stalls permanently at 95%) and #94335 (the tool_result IS delivered and the turn still never continues). A watchdog keyed on outstanding tool calls catches only this issue. The formulation that covers all three is "a turn is marked in progress while the event loop has no registered work for N seconds". Note also that this failure is invisible from the parent side when it happens in a background agent: the Agent tool's tool_result is the immediate "Spawned successfully" string, so the parent's pending-call bookkeeping always balances no matter what happens to the agent afterwards.

Impact: the session is unrecoverable in place and queued user messages are stranded, though they remain readable in the transcript as queue-operation/enqueue records and --resume restores state through the last complete turn.

Paths, hostnames, repository names, session ids and tool-use ids in this report are replaced with placeholders. Byte sizes, timestamps and counts are unmodified.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions