cloudflare / cloudflare/workerd
Bug: workerd segfaults intermittently on shutdown under vitest-pool-workers (linux-x64 and macOS-arm64)
- Dominant language
- C++
- Stars
- 8.7k
- Forks
- 739
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 174
Description
## Summary
`workerd` intermittently segfaults (`Received signal #11`) when miniflare tears down a worker between vitest test files. Tests inside the file run to completion and report passing before the crash, so the failure mode is purely shutdown-time noise — but vitest's cloudflare-pool sees the unexpected WebSocket close and raises `Worker exited unexpectedly`, failing the run with exit 1 despite 100% test pass rate.
Reproduces on **linux-x64** (GitHub Actions self-hosted runner, Ubuntu) and **macOS-arm64** (Darwin 25.4.0, M-series) with the same workerd binary. Confirmed with both `workerd-linux-64@1.20260507.1` and `workerd-linux-64@1.20260508.1` — not a recent regression.
## Versions
- `@cloudflare/workerd-linux-64` `1.20260508.1` (also `1.20260507.1`)
- `@cloudflare/vitest-pool-workers` `0.16.4`
- `miniflare` `4.20260508.0`
- `wrangler` `4.90.1`
- `vitest` `4.1.6`
- `node` `25.6.2`
## Symptoms
Run summary from a CI failure:
```
Test Files 34 passed (39)
Tests 400 passed (400)
Errors 5 errors
Duration 63.70s
Exit status 1
```
Every test that executed reported as passed; the run still fails because 5 of 39 worker shutdowns segfaulted. Each segfault produces:
```
*** Received signal #11: Segmentation fault
stack: …/workerd-linux-64@1.20260508.1/…/workerd@ …
```
The crash addresses differ across the 5 crashes within a single run — some start at `workerd@24e613f`, others at `workerd@5359d1b → 52a32e9 → 52ce098 → 52b3716 → 24e64a3`, others at `workerd@52a32c7 → 52ce0ef → 52b46bf → 52b25b5 → 52b2ed4 → 24e666f`. All chains converge on the same deep frames (`workerd@24e66cf` repeated many times), which look like the event-loop entry. Suggests multiple distinct call sites all reaching the same crashing teardown path.
Vitest then reports:
```
⎯⎯⎯⎯⎯⎯ Unhandled Error ⎯⎯⎯⎯⎯⎯⎯
Error: [vitest-pool]: Worker cloudflare-pool emitted error.
Caused by: Error: Worker exited unexpectedly
❯ _WebSocket.emitUnexpectedExit …/vitest/dist/chunks/cli-api.B5majYba.js:3012:33
❯ _WebSocket.[kClose] …/miniflare/dist/src/index.js:58868:37
```
## Frequency
About **5 segfaults per 39 sequential test files** (~13% per shutdown) in our integration suite. Each crashed file gets dropped from the file-pass counter (`34 passed (39)`), even though its 30-odd test cases already reported back as passed inside the `400 passed (400)`.
## What does NOT help
- `maxWorkers: 1` + `fileParallelism: false` in `vitest.config.ts` (sequential execution — workers still segfault on the per-file teardown)
- Downgrading the workerd binary one patch (May-7 → same shape)
- Single-file runs (`vitest run path/to/one.test.ts`) — never reproduce. Only the multi-file sequential run hits the threshold.
## Difference from #6583
[#6583](https://github.com/cloudflare/workerd/issues/6583) is a deterministic startup-time crash in `kj::Path::evalPart` → `ModuleRegistryImpl::resolve` triggered by importing `node:sqlite` on macOS. This is a **stochastic shutdown-time crash** that doesn't depend on test content (different files crash across runs), reproduces on linux-x64 too, and only manifests after the per-file teardown — test bodies run to completion first.
## Ask
Any guidance on:
1. A graceful-shutdown knob in miniflare/workerd we could enable to sidestep the crash path?
2. Whether the addresses (`workerd@24e66cf`, `workerd@52ce098`, `workerd@52b3716`) can be resolved to source lines against the published binary so we can narrow down the call site?
3. Whether this looks like a known fixed-in-main issue we should expect in a later release.
Happy to gather more diagnostics (`ulimit -c unlimited` + coredumpctl, `MINIFLARE_WORKERD_PATH` with a debug build, etc.) if useful.
Contributor guide
Assessment
This issue has not been assessed yet.