github / github/copilot-cli

Copilot CLI crashes on exit (Windows) — libuv `uv_async_send` on a closing handle (FAST_FAIL_FATAL_APP_EXIT)

Aberta
#4,217 0 comentários 1 reação 0 responsáveis Ver no GitHub
area:platform-windows
Linguagem predominante
Shell
Estrelas
11.2k
Forks
1.9k
Merge médio
14h 16min
PRs com merge (30d)
6

Descrição

### Describe the bug

On Windows x64, `copilot.exe` **consistently crashes at process exit** with a fatal
fail-fast (`0xc0000409`, subcode `0x7 FAST_FAIL_FATAL_APP_EXIT`). The session's work
completes normally; the crash happens only during teardown.

Live-debugger analysis (WinDbg attached to the crashing process) shows this is the
well-known **Windows-only Node.js/libuv shutdown race** — `uv_async_send()` is called
on a `uv_async_t` whose `UV_HANDLE_CLOSING` flag is already set, tripping the libuv
assertion:

```
Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), file src\win\async.c
```

which calls `abort()` → `__fastfail(FAST_FAIL_FATAL_APP_EXIT)`. The bundled Node
(v24.16.0) ships libuv with this assertion **enabled**, so the otherwise-benign
teardown race becomes a hard crash.

Upstream tracking issue: https://github.com/nodejs/node/issues/56645
(Node 23/24/25 lines on Windows; Linux/macOS unaffected.)

### Affected version

- **GitHub Copilot CLI:** 1.0.74-0 (crash first captured on 1.0.73.0; reproduces on 1.0.74-0) - **Bundled Node.js:** v24.16.0 (win-x64, single-executable build), ICU 78 - **OS:** Windows x64 (build 10.0.29635) - **Onset:** started ~1 month ago (consistent with a CLI update that bumped the bundled Node)

### Steps to reproduce the behavior

1. Launch `copilot` on Windows x64.
2. Use it normally (any session involving network/async activity).
3. Exit the CLI.
4. The process aborts on exit with a fail-fast crash / WER entry (exit is not clean).

Reproduces every time on the affected machine.

### Expected behavior

The CLI should exit cleanly (exit code 0, no fail-fast/WER crash) after the session ends.

### Additional context

Two threads show both sides of the shutdown race:

**Crashing thread — "V8Worker" (a V8 background platform worker):**
```
copilot!uv_async_send+0x3a
→ _wassert("!(handle->flags & UV_HANDLE_CLOSING)", "src\win\async.c", 94)
→ abort()
→ __fastfail(FAST_FAIL_FATAL_APP_EXIT) ; int 29h, rcx=7
```
Disassembly of `uv_async_send` confirms the fatal branch is the top-of-function
guard (`test byte ptr [handle+0x58],1` / `UV_HANDLE_CLOSING`), not a failed
`PostQueuedCompletionStatus`.

**Main thread — in Node's process-exit teardown, joining workers:**
```
node::DefaultProcessExitHandler
→ (V8 platform shutdown)
→ uv_thread_join
→ WaitForSingleObjectEx ; waiting for the V8 worker to exit
```

So during `DefaultProcessExitHandler`, the main thread closes the per-isolate
"flush-tasks" `uv_async_t` (sets `UV_HANDLE_CLOSING`) and joins the V8 workers; a
V8 worker drains one last task and calls `uv_async_send()` on that now-closing
handle → assertion → abort.

`!analyze -v` summary:
- `ExceptionCode: c0000409` (STATUS_STACK_BUFFER_OVERRUN), `Subcode: 0x7 FAST_FAIL_FATAL_APP_EXIT`
- `FAILURE_BUCKET_ID: FAIL_FAST_FATAL_APP_EXIT_c0000409_copilot.exe!Unknown`
- Faulting thread is the V8 worker; instruction is `int 29h` (`__fastfail`).

## Suggested fixes (for maintainers)
- Avoid `process.exit()` during teardown when V8/libuv async handles are still
live; prefer setting `process.exitCode` and letting the loop drain, or add a
small deferral before forced exit (common community workaround for #56645).
- Ship a Node build with the libuv fix for nodejs/node#56645 once available, or a
Node line where the shutdown ordering doesn't hit this path on Windows.
- Impact is at-exit only (no data loss), but it produces a non-zero exit and a WER
crash entry on every exit, which is noisy and can break scripts that check the
CLI's exit code.

Guia de contribuição

Abrir o guia de contribuição

Direção de pesquisa

Comece rastreando o Node DefaultProcessExitHandler e o desligamento da plataforma V8 descritos no relatório, concentrando-se no caminho de process.exit e no uv_async_t de flush-tasks por isolate. Reproduza o crash de saída no Windows x64 e compare o comportamento do Node v24.16.0 incluído com a issue de acompanhamento upstream nodejs/node#56645. Considera-se concluído quando copilot sair corretamente com o código 0 e não ocorrer nenhum crash de fail-fast ou WER.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
node.js
Domínio
cli
Tipo de issue
Bug
Dificuldade
4/5
Tempo estimado
3-5 dias
Status de atividade
Pouca atividade
Clareza
Razoavelmente clara
Facilidade para iniciantes
48/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.