Resumed long sessions render all messages as React components, causing 10s+ keypress lag

Resolved 💬 2 comments Opened Feb 13, 2026 by Osso Closed Mar 14, 2026

Description

Resuming a long-lived session causes the TUI to become completely unusable — 10+ second delay per keypress, 7.5 GB RSS, 110% CPU. The root cause is the M21 message rendering component rendering every message in history as a React/Ink component without virtualization.

Root Cause Analysis

The message list component (M21 / v8H in the minified bundle) builds a renderable array from the full conversation:

// M21 component (deminified)
let z = useMemo(() => [...normalizedMessageHistory, ...normalize(messages).filter(gs)], [messages, normalizedMessageHistory])

In transcript mode, there's a limit: OdH = 10 — only the last 10 messages render. But in the normal prompt screen (d = false), no limit applies:

let MH = d ? AH.slice(-OdH) : AH  // d=false in prompt mode → MH = AH (all messages)

Then every message gets a React element:

v.map(($H, AH) => createElement(ycD, { key:..., message: $H, ... }))

On resume, normalizedMessageHistory is populated from the full JSONL session log. With a long session, this means thousands of React components rendered for messages that aren't even visible on screen.

Evidence

Session stats (session af1bd7fd, project wow-ui-sim):

  • 35 MB JSONL file, 5,716 lines
  • 1,174 assistant messages, 720 user messages, 696 tool use blocks
  • 5 context compactions (session continued multiple times)
  • ~1,894 renderable message components

Process behavior:

  • 110% CPU, 7.5 GB RSS on resume
  • perf profile: dominated by madviseunmap_page_rangeclear_page_ermsflush_tlb_mm_range (V8 GC thrashing)
  • strace: 66% restart_syscall, 20% futex, 12% sched_yield — busy-wait from GC pressure
  • Keypress latency: ~10 seconds (completely unusable)

Comparison with normal session:
| | Normal session | Slow session |
|---|---|---|
| JSONL size | 0.5 MB | 35 MB |
| Messages | 138 | 1,894 |
| Tool uses | ~20 | 696 |
| RSS | 500 MB | 7,500 MB |
| CPU idle | 40% | 110% |
| Keypress lag | instant | ~10s |

Proposed Fix

Apply the same OdH = 10 limit (or similar) to the prompt screen, not just transcript mode. Messages scrolled off the terminal aren't visible anyway. Alternatively, virtualize the message list to only render what's in the viewport.

Steps to Reproduce

  1. Use a session heavily over many hours with many tool calls (or find/create a large JSONL session file)
  2. Exit the session
  3. Resume with claude --resume <session-id>
  4. Try typing — observe multi-second keypress lag

Environment

  • Claude Code 2.1.39
  • Linux (Arch), AMD Ryzen AI 9 HX PRO 370 (24 threads, 54 GB RAM)
  • Terminal: Ghostty

Related Issues

  • #19934 — same symptoms on resume, reporter saw 40 GB memory, had 10 GB conversation file
  • #22968 — gradual degradation in long sessions (same root cause, slower onset)
  • #17142 — idle CPU from sched_yield/futex (related idle spinning)

View original on GitHub ↗

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