[BUG] Idle session pinned at ~100% CPU — event-loop busy-spin (kevent64 immediate-return) on macOS ARM64, v2.1.177

Open 💬 3 comments Opened Jun 16, 2026 by echo-layker

Summary

On macOS (Apple Silicon), idle Claude Code CLI sessions intermittently get pinned at ~100% CPU with the main thread stuck in an event-loop busy-spin. This happens with no user activity and no agent task running — the machine heats up and fans spin while the terminal becomes laggy / unable to accept input. This looks like the same class of problem as #17148, #10493, #21006, #18532, #22275, #19393, #11122.

I'm attaching 5 consecutive /usr/bin/sample captures that pin down the spin, in case the stacks help.

Environment

  • Claude Code: v2.1.177
  • OS: macOS 15.7.3 (24G419), Apple Silicon (ARM64)
  • Launched via: claude --dangerously-skip-permissions (several long-lived sessions, some via --resume, parent zsh)
  • Several MCP servers / plugins active (oh-my-claudecode bridge, codegraph MCP, etc.)

What happened

Activity Monitor showed three separate claude (shown as 2.1.177) processes each at 99.7–99.9% CPU simultaneously, with huge accumulated CPU time while the machine was idle:

| PID | Elapsed | Accumulated CPU time |
|-------|-------------|----------------------|
| 12343 | 1d 14h | ~4h38m |
| 30623 | 9h 37m | ~3h20m |
| 57104 | 8h 56m | ~2h27m |

These were idle sessions (no prompt running) yet had burned hours of CPU.

Evidence (sampling)

I captured the worst offender (pid 12343) with sample 5 times in a row. Key observations:

  1. All 5 captures are byte-for-byte identical → the process is locked in a stable repeating state.
  1. The main thread (com.apple.main-thread) sits in the event loop with kevent64 returning immediately and being re-armed in a tight loop (note the varied return offsets), rather than blocking:
2156 start (in dyld)
  2156 ??? (in 2.1.177) ...   <-- main entry
    1781 ??? (in 2.1.177) + 0x1014354
    ! 1649 ??? (in 2.1.177) + 0x85dc04
    ! : 1640 kevent64 (in libsystem_kernel.dylib) + 8,4,...   <-- spinning, immediate return
  1. "Sort by top of stack" is dominated by waiting/polling primitives (worker threads parked, main loop churning), with no single hot compute frame — the classic signature of a wake/poll storm rather than real work:
__psynch_cvwait   21560
__ulock_wait2     21560
kevent64           3796
mach_msg2_trap     2156

This lines up with #17148 (uv__run_check → CheckImmediate → setImmediate() busy-wait) and #10493 (non-blocking poll + immediate retry), except on macOS the spin surfaces through kevent64 instead of epoll_pwait.

Recovery behavior (matches #21006)

When the terminal was frozen and unresponsive, simply opening a new Claude session knocked the stuck session out of the spin — without killing it. Right after, the stuck PIDs dropped to ~0.1–0.3% CPU and their accumulated CPU time stopped growing (only +0.2–0.4s over several minutes). The process stayed alive but idle. This is the same "new session in the same dir recovers it" behavior reported in #21006.

So it appears to be an intermittent UI/event-loop spin that a terminal state change (SIGWINCH / focus / foreground-pgrp change) can break out of.

Contributing factor

Multiple long-lived idle sessions accumulating in the background made this much more likely / more impactful (9+ claude processes were running, several 8h–2d old) — consistent with #11122.

Sample files

Full 5 captures (no sensitive data — sample auto-redacts user paths to /Users/USER/*, and the binary is stripped):

👉 https://gist.github.com/echo-layker/1d38915d4cbdfa27de2672a21cc22f21

Repro

Intermittent. Leave one or more claude sessions open and idle for hours on macOS ARM64; some sessions eventually enter the 100% CPU spin. Hard to trigger on demand.

View original on GitHub ↗

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