anthropics / anthropics/claude-code

[BUG] Windows: ~5s event-loop stall on first Enter after idle — working-set trim causes 41k major page faults (duplicate message submission)

Ouverte
#93,372 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub
area:tui bug has repro platform:windows
Langage dominant
Python
Étoiles
145k
Forks
23.1k
Métriques de merge des PR
Métriques de PR en attente

Description

## Summary

On Windows, after a session has been idle for a couple of minutes, the first `Enter` does not
register for ~5 seconds. The TUI does not repaint, so it looks like the keystroke was dropped —
users press `Enter` again, and both newlines are delivered when the block clears, submitting the
message twice.

Claude Code's own `[event-loop-stall]` detector catches it and the WARN line contains the cause:
the Node event loop is blocked taking **tens of thousands of major page faults**, because Windows
has trimmed the idle process's working set out to disk.

**The machine is not short of memory when this happens.** In the capture below there was
**12.5 GB of RAM free** and commit was at 62%. Windows trims the working set because the process
is *idle*, not because of memory pressure — so this reproduces on well-provisioned machines and
is not fixed by closing other apps or adding RAM.

## The evidence

Captured with `claude --debug-file `, build 2.1.261.355, Windows 11 (10.0.26200), 32 GB RAM.
Session had been idle 2m25s. User pressed Enter at 19:56:10.8 local.

Last log line before the block:

```
14:26:10.819Z [DEBUG] Hooks: checkForNewResponses returning 0 responses
```

Then, 5 seconds later:

```
14:26:15.864Z [WARN] [event-loop-stall] blocked for 4940ms monotonic (wall drift 4940ms,
clock jump 0ms, expected 200ms). Total stalls: 1, cumulative: 4940ms monotonic / 4940ms wall
blocked_write=false last_write=0ms/2145B sigcont=false
cpu=77ms majflt=41105 rss=664MB heap=151MB ext=63MB
```

Reading the fields:

| field | value | what it rules out |
|---|---|---|
| `majflt=41105` | 41,105 major page faults | this is the mechanism — pages fetched from disk |
| `cpu=77ms` | 77 ms CPU across 4,940 ms (1.6%) | not CPU-bound work, not GC |
| `clock jump 0ms` | no wall/monotonic divergence | machine did not sleep or hibernate |
| `sigcont=false` | not suspended/resumed | not OS process suspension |
| `blocked_write=false` | terminal write path clear | not the renderer, not ConPTY backpressure |

Immediately after unblocking, the UserPromptSubmit hooks run and the TUI issues one full repaint
of everything it owed:

```
14:26:16.046Z [DEBUG] Hook output does not start with {, treating as plain text
14:26:16.092Z [DEBUG] High write ratio: blit=0, write=18684 (100.0% writes), screen=307x156
14:26:16.127Z [DEBUG] [API REQUEST] /v1/messages ... source=repl_main_thread
```

An external sampler confirms it independently, watching the same process across the same seconds
(`cpu% : working_set_MB : private_MB`):

```
19:56:08.9 9.8 : 504 : 834
19:56:11.2 9.0 : 607 : 835 <- Enter; block begins
19:56:13.4 0.0 : 638 : 835 <- 0% CPU, inside the block
19:56:15.6 0.0 : 661 : 835 <- 0% CPU, inside the block
19:56:17.8 12.0 : 714 : 946
19:56:28.9 10.6 : 946 : 858
19:56:31.3 4.8 : 946 : 858 <- settles
```

Working set climbs **504 MB → 946 MB** while private (committed) bytes stay flat at ~834–858 MB.
Committed-but-not-resident is memory that is on disk. That is a fault-in, not an allocation.

## Impact

1. **Enter appears to do nothing for ~5 s.** The prompt *is* accepted and stamped into the
transcript immediately; it is the hooks and the repaint that are late, so there is no visual
feedback at all during the block.
2. **Duplicate message submission.** The natural response — pressing Enter again — is buffered
and delivered on unblock. This is the most damaging symptom, and it reads to the user as a
separate bug.
3. **Apparent render garbling**, from the single large catch-up repaint.

## Reproduction

1. Windows, a session with a large context (~150 MB heap / ~950 MB private bytes here).
2. Leave it idle 2+ minutes while other processes are active.
3. Type a message and press Enter once.
4. `grep "event-loop-stall" | grep WARN`

Reproduces on **2.1.260 through 2.1.266** — this is not a regression from any one build. Six
concurrent sessions on this machine all sat 40–60% non-resident after a few idle minutes.

## Notes toward a fix

I don't know which allocation the loop touches first on prompt submit, but the fault storm implies
something walks a large structure synchronously in that path. Two observations that may help:

- The faults are serviced as ~41k individual page faults. Reading the same process's committed
private regions sequentially from an external process faults **442 MB back in 441 ms** — roughly
**10x faster** than the process does it for itself, which is what you would expect from
read-ahead clustering on sequential access versus scattered single-page faults. So part of the
cost is the access *pattern*, not the volume.
- `[event-loop-stall]` already carries everything needed to diagnose this. Surfacing a hint in the
TUI when a stall exceeds a threshold ("catching up, one moment") would remove the duplicate-submit
symptom even without fixing the underlying fault storm, because the user would stop pressing Enter.

## Workaround, for anyone landing here

Wait ~5 s rather than pressing Enter again. If you want it gone, touching each `claude.exe`'s
committed private memory from an external process on a ~90 s timer keeps the working set resident;
a pass costs ~60 ms when nothing has been trimmed. Note this needs no Windows setting change and
no working-set quota call.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Piste de recherche

No source file or test is named. Reproduce on Windows after two minutes idle using --debug-file, then inspect the prompt-submit path and the existing [event-loop-stall] detector while comparing major page faults and repaint timing. Done should be demonstrated by eliminating the post-idle stall and duplicate submission, or by providing clear catch-up feedback that prevents the second Enter.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
node.js
Domaine
cli, operating-systems, performance
Type d'issue
Bug
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
Active
Clarté
Plutôt claire
Accessibilité débutants
38/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.