Claude Code freezes/hangs with no input accepted — 100% write ratio in terminal renderer

Status Open
Reported on v2.1.39
Maintainer reply None cached
Activity 20 comments · opened Feb 12, 2026

Description

Claude Code CLI sessions become completely unresponsive — no keyboard input is accepted (Ctrl+C, Ctrl+D, typing all ignored). The process stays alive but the UI is frozen. The only recovery is to kill the process from another terminal.

This has happened at least 5 times in the past few days. Two frozen sessions were caught running simultaneously today.

Version & Environment

  • Claude Code: 2.1.39
  • OS: macOS 26.2 (Build 25C56), Apple Silicon (arm64, T6041)
  • RAM: 24 GB
  • Terminal: Apple Terminal 466
  • Shell: /bin/bash

Reproduction

Occurs during long conversations with many tool calls (Slack API, file reads, MCP server interactions). No SSH commands, no large file reads, no massive output — normal usage with moderate-sized API responses.

Frozen Session Details

Session 1 (PID 37894) — frozen ~15h 43m

  • Debug log: f206e0fe-fcf9-4e49-8767-897226513853.txt (3.5MB)
  • Message count at freeze: 747 deferred messages
  • Token count at freeze: 121,004 / 167,000 threshold
  • Last log entries: High write ratio: blit=0, write=86776 (100.0% writes), screen=1299x143
  • Freeze time: 2026-02-12T05:52:02Z
  • Pattern: API request made → stream started → high write ratio loop → silence

Session 2 (PID 58385) — frozen ~9h 14m

  • Debug log: 1474e176-7d40-404d-bc27-2fd1459e3619.txt (2.1MB)
  • Message count at freeze: 1,170 deferred messages
  • Token count at freeze: 156,796 / 167,000 threshold (very close to threshold!)
  • Last log entries: High write ratio: blit=0, write=80922 (100.0% writes), screen=1850x95
  • Freeze time: 2026-02-12T14:07:48Z
  • Pattern: identical — API request → stream chunk received → high write ratio → silence

Common Pattern Across All Freezes

  1. Debug logs show High write ratio: blit=0, write=80000-87000 (100.0% writes) — the terminal renderer is doing zero blits and 100% full-screen writes every frame
  2. The [useDeferredValue] Messages deferred by 1 count climbs into the hundreds/thousands
  3. An API request is made, a stream starts, and then the process goes silent
  4. No error, crash, OOM, or signal logged — it just stops writing to the debug log
  5. The process remains alive (S+ state in ps) but accepts no input

Historical Occurrences

Scanning all debug logs, at least 4 sessions ended with this exact 100.0% writes pattern:

  • 2026-01-28 (d1a5eb06) — write=1333
  • 2026-02-04 (ca45a690) — write=1163
  • 2026-02-11 (b26b881d) — write=56639
  • 2026-02-12 (f206e0fe) — write=86776

The write counts have been growing over time, suggesting the issue gets worse with longer/more complex conversations.

Hypothesis

The terminal renderer appears to enter a state where it can only do full-screen rewrites (0 blits) with very large write buffers (80-87KB per frame). Combined with high message counts (700-1170 deferred messages) and token counts near the autocompact threshold, this seems to cause the event loop to block, preventing input handling.

Session 2 was at 156,796/167,000 tokens (94% of threshold) — the proximity to the autocompact threshold may be a contributing factor.

Environment Notes

  • Multiple MCP servers active (gdrive, slack, gmail) per session
  • Using Apple Terminal (not iTerm2 or other alternatives)
  • Conversations involve frequent Slack API calls with JSON responses

🤖 _This bug report was written with AI assistance (by Claude Code itself, analyzing its own debug logs)_

View original on GitHub ↗

13 Comments

github-actions[bot] · 6 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/21567
  2. https://github.com/anthropics/claude-code/issues/25243
  3. https://github.com/anthropics/claude-code/issues/24688

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

tamasarpad · 6 months ago

Happened to me as well on 2.1.39 under MacOS. Couldn't even kill the process, the whole container and Docker VM froze.

karbassi · 6 months ago

Additional report

Experiencing the same freeze behavior on v2.1.42.

Environment

  • Claude Code: 2.1.42
  • OS: macOS 26.3 (Build 25D5087f), Apple Silicon (arm64, M1)
  • RAM: 16 GB
  • Terminal: Ghostty (TERM=xterm-ghostty)
  • Shell: fish
  • tmux: 3.6a (also reproduces without tmux)

Reproduction

  • Freezes occur randomly during normal usage — not tied to any specific action
  • Display freezes completely; typed input passes through but is not rendered
  • Ctrl+L does not recover the display
  • Ctrl+C / Ctrl+D unresponsive
  • Only kill -9 recovers

Isolation testing

  • SSH + tmux: freezes
  • SSH, no tmux: freezes
  • Ruled out tmux config (allow-passthrough, escape-time, status bar scripts) — none made a difference
  • Freezes started appearing within the last ~10 hours of usage

Consistent with the terminal renderer entering the 100% full-screen write loop described in the original report.

bdmorin · 6 months ago

Additional report — idle-prompt freeze with 176 unique screen sizes

Confirming this bug on v2.1.58. Session froze at the idle prompt (not during streaming), making Ctrl+C / Ctrl+D / all input unresponsive. Only kill from another terminal recovers.

Environment

  • Claude Code: 2.1.58 (auto-updated to 2.1.59 binary while frozen process was still running)
  • OS: macOS 26.2 (Build 25C56), Apple Silicon M3 Pro
  • RAM: 18 GB
  • Terminal: iTerm2 3.6.6
  • Shell: fish
  • Permission mode: --dangerously-skip-permissions

Key evidence from debug log

176 unique screen sizes observed in a single session (widths ranging from 21 to 1718 columns). This appears to be iTerm2 pane resizing, and likely forces full redraws each time.

Total 'High write ratio' entries: 435
Total blit=0 (100% full redraw) entries: 368 (85% of renders)
Debug log: 5,548 lines / 554 KB
Session runtime: ~3h 45m (21:44 → 01:29 UTC)

Terminal sizes at freeze point:

screen=1675x171  → blit=21717, write=103058 (82.6% writes)
screen=1677x171  → blit=0,     write=112171 (100.0% writes)  ← full redraw spike
screen=1689x171  → blit=21717, write=103590 (82.7% writes)

New observation: freeze occurs at idle prompt, not during streaming

Unlike the original report where the freeze occurs during active API streaming, this session froze after the turn completed:

23:56:10 — Stop hooks fired successfully
23:56:10 — Stopped caffeinate, allowing sleep
23:56:13 — prompt_suggestion forked agent completed
23:57:10 — idle_prompt notification fired
           ← session is now idle, waiting for user input →
00:17:03 — OTEL telemetry export timeout (ECONNABORTED, 10000ms)
01:07:53 — Auto-update download stalled on attempt 1/3, retried
01:08:01 — Binary updated from 2.1.58 → 2.1.59 (symlink swapped while process still running)
01:22-25 — High write ratio loop continues, process unresponsive

The session was sitting at the prompt for ~1.5 hours before the first error appeared. The renderer never stopped its high-write-ratio loop even in idle state.

Context state at freeze

autocompact: tokens=87985 threshold=167000 effectiveWindow=180000
Messages deferred: 458

Token count was well under the compaction threshold (52% of limit), so this isn't a near-threshold issue like Session 2 in the original report.

Compounding factors observed

  1. OTEL telemetry timeout at 00:17 — ECONNABORTED, timeout of 10000ms exceeded (1P and 3P export both failed)
  2. Auto-update binary swap at 01:08 — running process was 2.1.58, symlink swapped to 2.1.59
  3. Config lock contention earlier in session — Failed to save config with lock: Error: Lock file is already being held
  4. 176 unique screen sizes — constant iTerm2 pane resizing likely prevents the renderer from stabilizing its diff/blit state

Hypothesis addition

The original report focuses on high message counts and near-threshold token counts as contributing factors. This case shows the freeze can also occur with moderate token counts (52%) and moderate message counts (458) — suggesting the screen size itself (1675+ columns, 171 rows) is sufficient to trigger the pathological render loop regardless of conversation size.

The 176 unique screen sizes may also be relevant — if the renderer's diff algorithm resets its baseline on every resize, it would never get a chance to blit incrementally, keeping it in the 100%-write-ratio state permanently.

cafe24-mcpark · 5 months ago

Additional diagnostic data: Freeze during idle state (macOS, Apple Silicon)

Adding diagnostic findings from a freeze that occurred during idle (not during active API call), which may suggest a different trigger path for the same underlying bug.

Environment

  • Claude Code: 2.1.68 (frozen session) / 2.1.69 (current)
  • OS: macOS 26.2 (Darwin 25.2.0), Apple Silicon (arm64)
  • Terminal: iTerm2
  • Shell: zsh
  • Node: v25.6.0

Symptoms

  • Session was idle (~4+ minutes after last stream completed, Stop event logged)
  • Screen visible, TUI rendered normally, but zero keyboard input accepted
  • Process alive in kevent64 wait (normal event loop state)
  • No crash, no error, no OOM, no signal
  • Required kill from another terminal + claude --continue to recover

Diagnostic findings (frozen vs working session comparison)

All external state was identical between the frozen session and a healthy session running simultaneously:

| Check | Frozen (ttys015) | Working (ttys008) | Match? |
|-------|-----------------|-------------------|--------|
| tty raw mode | -icanon -isig -iexten -echo | same | ✅ |
| Process state | kevent64 (event loop wait) | same | ✅ |
| PGID == TPGID (foreground) | yes | yes | ✅ |
| fd layout (tty + pipes) | 0-2: tty, 3+: pipes | similar | ✅ |
| Process sampling (all threads) | main: kevent64, workers: pthread wait | same | ✅ |

Key difference from other reports

This freeze occurred during idle — the session had completed its last API stream 4+ minutes prior and was waiting for user input. Previous reports (#25286, #25243) describe freezes during active API calls or long streaming responses. This suggests the renderer lock-up can also happen post-stream, possibly during autocompact or deferred message processing.

Conclusion

Since all external state (tty settings, process groups, file descriptors, thread states) is identical between frozen and working sessions, the freeze is internal to the TUI framework — likely Ink/React stdin reader detachment or event loop blockage that cannot be diagnosed without debug symbols or internal instrumentation.

A built-in health check / watchdog mechanism (e.g., periodic stdin responsiveness self-test) would allow detection and auto-recovery of this state.

balavishnuvj · 5 months ago

Additional report — Zombie process accumulation after freeze

Confirming this bug on v2.1.63 / 2.1.70 / 2.1.71 with Ghostty on macOS 26.2 (Darwin 25.2.0), Apple Silicon

Post-freeze zombie accumulation

After the freeze occurs (matching the TUI renderer 100% write-ratio loop described above), closing the frozen terminal tab leaves behind zombie processes that never exit. Found 25 of 34 Claude processes in this state on my machine — all
with revoked FDs and every thread deadlocked on _os_unfair_lock_lock_slow → __ulock_wait2. These accumulate indefinitely (observed 8+ days old), each holding 10-20 MB RSS.

This suggests Claude CLI doesn't handle SIGHUP (terminal hangup) — when the TTY is destroyed after closing a frozen tab, the process enters a mutex deadlock instead of exiting.

Cleanup for affected users

Kill all orphaned Claude processes (those with no controlling TTY)
```sh
ps -eo pid,tty,comm | grep -w claude | grep '??' | awk '{print $1}' | xargs kill -9


  Suggested secondary fix

  Beyond fixing the renderer freeze itself, a SIGHUP handler or FD watchdog that detects revoked stdin/stdout and self-terminates would prevent zombie accumulation.
ZdenekCulik · 5 months ago

Guys! I solve this! This was the issue!

Here's what was wrong -- three separate bugs stacking on top of each other:
Bug 1: macOS 26 (Tahoe) blocks shebang execution on npm-installed files
When you installed Claude Code via npm install -g, macOS automatically tagged every file with a com.apple.provenance extended attribute. On macOS 26, this attribute causes the kernel to hang indefinitely when executing scripts via shebang (#!/usr/bin/env node). The process would freeze at _dyld_start -- the very first instruction of the dynamic linker -- before Node.js even loaded. This is why Claude Code appeared completely frozen: it literally never started.
Fix: A claude() shell function in ~/.zshrc that calls /usr/local/bin/node cli.js directly, bypassing the broken shebang path entirely.
Bug 2: File descriptor limit of 256 caused EMFILE crashes
Ghostty inherited a soft ulimit -n of 256 from macOS's launchctl. When Claude Code spawned npm run dev, the Next.js file watcher quickly exceeded this limit, flooding the terminal with EMFILE: too many open files errors and overwhelming the TUI renderer.
Fix: ulimit -n 10240 at the top of ~/.zshrc.
Bug 3: Hardcoded "npm deprecation" warning in Claude Code 2.1.74
Claude Code's source has two mechanisms that fought against us: (a) auto-detection logic that found the empty ~/.local/share/claude/versions/ directory (left over from the uninstalled native binary) and kept overwriting installMethod back to "native", and (b) a hardcoded notification that fires whenever it detects it's running from npm, regardless of any config. The only way to suppress it is an undocumented DISABLE_INSTALLATION_CHECKS environment variable found by reading the minified source code.
Fix: Removed the empty ~/.local/share/claude/ directory and added DISABLE_INSTALLATION_CHECKS=1 to both settings files.

muarifer · 5 months ago
Guys! I solve this! This was the issue! 2: File descriptor limit of 256 caused EMFILE crashes Ghostty inherited a soft ulimit -n of 256 from macOS's launchctl. When Claude Code spawned npm run dev, the Next.js file watcher quickly exceeded this limit, flooding the terminal with EMFILE: too many open files errors and overwhelming the TUI renderer. Fix: ulimit -n 10240 at the top of ~/.zshrc

Works as a charm!

shinglokto · 5 months ago

Confirming on v2.1.87 (macOS 26.3.1 ARM64, Ghostty). Quick diagnostic without debug logs — just standard Unix tools:

# Check if an idle session has the render loop (offset should NOT increase)
lsof -p <PID> | grep "0u.*ttys"
sleep 3
lsof -p <PID> | grep "0u.*ttys"

On affected session: ~2KB/sec continuous writes. On healthy session: 0 bytes. The loop persists even after input recovers — it just drops from ~35% CPU to ~13%, enough for keypresses to get through.

benjaminrigaud-gg · 3 months ago

Reproducing on Linux/Ghostty with one twist worth flagging.

Environment

  • Claude Code 2.1.128 (Bun-backed)
  • Ubuntu 24.04.4 LTS, kernel 6.17.0-23-generic
  • Terminal: Ghostty (xterm-ghostty)

Same 100% write ratio, blit=0 pattern:

[DEBUG] High write ratio: blit=0, write=48701 (100.0% writes), screen=646x191

This is the same shape as your sessions 1 & 2 (blit=0, write=86776 (100.0%) / blit=0, write=80922 (100.0%)).

Twist: implausible screen= dimensions.

screen=646x191 is impossible for a real terminal — 646 rows would mean a ~7000-pixel-tall window. Throughout the same session, normal lines emit screen=44x144 (a real Ghostty pane). The 646x191 only appears during the stall window.

This suggests the renderer's cached screen-size state can be corrupted — possibly a resize event handled mid-stall, or a stale dimension stored by useDeferredValue after batched updates. The 100% write ratio then makes sense: at "646×191" the renderer thinks it must redraw a 123k-cell viewport each frame, never managing to blit.

Co-occurring symptoms in the same session:

  • 5 streaming stalls of 53–65 s each in 7 minutes (filed in #54434)
  • Heap retention growing ~1 GB / 7 min (filed in #56335)
  • Render stalls with identical blit/write counts repeating every 2–4 s

The render corruption appears to happen during event-loop blocks. If those blocks are major-GC pauses (per #56335), then anything async happening during the pause (resize, focus, scroll) could land in a corrupted state on the other side.

Repro is the same as yours: long session, many tool calls, MCP servers connected. Restarting the session clears it; the issue returns as the heap grows.

harshsharma2455 · 3 months ago

Complete Session Freeze — "continue" has no effect (Linux/Fedora)

Symptoms:

  • Two named sessions ("email-postmark" and "collugue") became completely unresponsive
  • Typing "continue" multiple times produced zero output or response
  • Sessions appeared alive but ignored all input; had to kill them
  • Not the same as the "silent pause" variant — no amount of input produced any response

Environment:

  • OS: Fedora 43 (Linux 6.17.12-300.fc43.x86\_64), Wayland, Konsole + tmux
  • Claude Code version: 2.1.156
  • Occurred during multi-step tasks with multiple tool calls (file edits, external API calls)

Pattern:
Happened in 2 separate named sessions across different projects. Both were mid-task sessions with a sequence of tool calls. After the freeze, the session was completely unresponsive — Ctrl+C, / commands, and repeated "continue" prompts were all ignored. Required killing the process from another terminal.

Different from pausing bugs: The workaround of typing "continue" that resolves similar issues does NOT work here. This appears to be a complete input loop freeze, not just a silent model generation stop.

0x1337ff · 1 month ago

Adding another data point - with a correction after closer observation: in my case it is not an input freeze. The session keeps accepting input and working normally; the symptom is a rendering artifact in the status line - ambiguous-width Unicode glyphs ( U+2665 and / U+25B0/U+25B1 progress bars in a custom statusLine command) eventually collapse into overlapping half-width cells mid-session, and stay broken until a full repaint or terminal restart.

Environment

  • Claude Code v2.1.206
  • macOS (Darwin 25.5.0, Apple Silicon)
  • Terminal: Ghostty
  • Custom statusLine bash command (refreshInterval: 60)

That puts my data point in the string-width / East-Asian-ambiguous-width family (#30471, #40323, #57368 - all closed as stale or duplicate, none actually fixed) rather than this render-loop freeze. Leaving this correction so it doesn't skew triage here - happy to file a fresh issue with before/after screenshots, since the width-family issues are all locked.

chkuendig · 1 month ago

for me, claude code starts severly slowing down in long running sessions (i have a few open on my homelab), just idling it for a day or two causes it to slow down to the point where input severely lags, and once registerd, the little "*finangling..." animation doesn't even update (or maybe only once a minute, I didn't check). other sessions started fresh in the same byobu run just fine - as do the slow downed one, once killed by hammering Ctrl-Z/Ctrl-C and resumed with claude --resume

Showing cached comments. Read the full discussion on GitHub ↗