vitest-dev / vitest-dev/vitest

`startVitest` with `runner: forks` has incorrect SIGTERM fallback on windows; fails to produce profiling logs

Open
#9,907 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

os: windows upstream
Dominant language
TypeScript
Stars
17.1k
Forks
2k
Avg merge
1d 22h
Merged PRs (30d)
94

Description

Describe the bug

Long story short, I made a script to run Vitest with Node.JS profiling logs enabled.

To my surprise, what should be an extremely simple task ended up being platform-dependent - no profiling output would be written when running on Windows machines.

Delving a bit deeper into Vitest source, it appears the SIGTERM workaround for nodejs/node#55094 is the culprit at hand:

https://github.com/vitest-dev/vitest/blob/fe9ed7ac857c2e3d44217f87ad78bc2f20c6b2be/packages/vitest/src/runtime/workers/init-forks.ts#L16-L28

Windows does not emit SIGTERM events on a process being killed (mapping to a native TerminateProcess API that kills without running handlers).
This means that --heap-prof and similar flags are effectively platform-dependent and will not work on non-Linux platforms.

[!IMPORTANT]
Switching to threads runner does solve the issue, though having the default runner option be platform-dependent is obviously not very ideal.

Reproduction
import { startVitest } from 'vitest/node';
import { glob } from 'node:fs/promises';
import { basename, join } from 'node:path';

const execArgv = [
  '--heap-prof',
  `--heap-prof-name=vitest.heapprofile`,
  `--heap-prof-dir=./temp`,
];
const vitest = await startVitest('test', undefined, { execArgv });
await vitest.close();

This outputs to ./temp only on UNIX-like systems vs. everything else.

MRE for SIGTERM behavior

import { fork } from "node:child_process";
import { writeFileSync } from "node:fs";

writeFileSync(
  "./example.mjs",
  `

process.on("SIGTERM", () => {
    // only runs on windows
    console.log("[child] SIGTERM received, exiting cleanly...");
    process.exit(0);
});
console.log("[child] Hello world");

// Keep alive
setInterval(() => {}, 1_000);
`,
  "utf8",
);

console.log(`Platform: ${process.platform}`);
console.log("[parent] Forking child...\n");

const child = fork("./example.mjs", { stdio: "inherit" });

// Give the child a moment to set up its SIGTERM handler
setTimeout(() => {
    console.log("\n[parent] Sending kill() to child (pid %d)...", child.pid);
    child.kill(); // sends SIGTERM on Linux; calls TerminateProcess on Windows

child.on("exit", (code, signal) => {
    console.log("[parent] Child exited — code: %s, signal: %s", code, signal);
});
}, 500);
Image Image

System Info
System:
    OS: Windows 11 10.0.26200
    CPU: (8) x64 AMD Ryzen 5 7520U with Radeon Graphics         
    Memory: 2.82 GB / 15.24 GB
  Binaries:
    Node: 24.14.0 - C:\Users\taylo\AppData\Local\Volta\tools\image\node\24.14.0\node.EXE
    npm: 11.9.0 - C:\Users\taylo\AppData\Local\Volta\tools\image\node\24.14.0\npm.CMD
    pnpm: 10.28.2 - C:\Program Files\Volta\pnpm.EXE
  Browsers:
    Chrome: 146.0.7680.80
    Edge: Chromium (140.0.3485.54)
    Internet Explorer: 11.0.26100.7309
  npmPackages:
    @vitest/coverage-v8: ^4.0.18 => 4.0.18 
    @vitest/expect: ^4.0.18 => 4.0.18 
    @vitest/utils: ^4.0.18 => 4.0.18 
    vite: ^7.3.1 => 7.3.1 
    vitest: ^4.0.18 => 4.0.18 
    vitest-canvas-mock: ^1.1.3 => 1.1.3

(The linux one was on stackblitz, also with vitest 4.0.18. I also have reproduced it working on my local WSL installation running Ubuntu, but it really doesn't matter.)

Used Package Manager

pnpm

Validations

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/vitest/src/runtime/workers/init-forks.ts at the linked SIGTERM workaround, then run the provided startVitest reproduction with runner: forks on Windows and a Unix-like system. Compare the process termination behavior and profiling output; done means the Windows run produces the expected profiling logs without regressing the Unix-like case.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.