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)

Abierto
#93,372 1 comentario 0 reacciones 0 asignados Ver en GitHub
area:tui bug has repro platform:windows
Lenguaje dominante
Python
Estrellas
145k
Forks
23.1k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

## 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.

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Línea de trabajo

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.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
node.js
Área
cli, operating-systems, performance
Tipo de issue
Error
Dificultad
5/5
Tiempo estimado
Más de una semana
Estado de actividad
Activo
Claridad
Bastante claro
Aptitud para principiantes
38/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.