Skip to content

fix: resolve vitest hang caused by mkdirSync on /proc#26145

Merged
dsyme merged 6 commits intomainfrom
fix/vitest-hang-proc-mkdir
Apr 14, 2026
Merged

fix: resolve vitest hang caused by mkdirSync on /proc#26145
dsyme merged 6 commits intomainfrom
fix/vitest-hang-proc-mkdir

Conversation

@dsyme
Copy link
Copy Markdown
Collaborator

@dsyme dsyme commented Apr 14, 2026

Problem

PR #26143 did not fix the vitest CI hang. The js job was still hanging for 7+ minutes: https://github.com/github/gh-aw/actions/runs/24377417814/job/71193722349

Root Cause

safe_output_manifest.test.cjs had a test that called:

writeTemporaryIdMapFile({}, "/proc/fake/map.json")

This internally runs fs.mkdirSync('/proc/fake', { recursive: true }) which hangs indefinitely on Linux because the procfs virtual filesystem blocks the recursive mkdir syscall. The vitest worker process would get stuck during test collection, causing the entire suite to freeze at safe_output_manifest.test.cjs 0/35.

The forceExit: true added by #26143 was a Jest concept — vitest accepts it syntactically but it did not reliably force-kill the hung worker.

Fix

  • Replace /proc/fake/map.json with /dev/null/fake/map.json — fails immediately with ENOTDIR since /dev/null is a file, not a directory
  • Remove forceExit: true from vitest.config.mjs — it masked the issue rather than fixing it, and with the root cause resolved it's no longer needed

Validation

  • safe_output_manifest.test.cjs: all 35 tests pass in ~280ms (previously hung indefinitely)
  • Confirmed the fix by bisecting all 35 tests to isolate the single hanging test

The JS test suite hung indefinitely because safe_output_manifest.test.cjs
called writeTemporaryIdMapFile({}, "/proc/fake/map.json") which internally
runs fs.mkdirSync('/proc/fake', { recursive: true }). This hangs on Linux
because the procfs filesystem blocks the recursive mkdir call.

Changes:
- Replace /proc/fake/map.json with /dev/null/fake/map.json which fails
  immediately (ENOTDIR) since /dev/null is a file, not a directory
- Remove forceExit: true from vitest.config.mjs (added by #26143 as a
  workaround, but it masked the real issue rather than fixing it)
Copilot AI review requested due to automatic review settings April 14, 2026 03:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR resolves a Linux-specific vitest hang during test collection caused by attempting fs.mkdirSync(..., { recursive: true }) under /proc.

Changes:

  • Updates safe_output_manifest.test.cjs to use a non-directory path under /dev/null so the failure is immediate (no hang).
  • Removes forceExit: true from vitest.config.mjs since it was masking the underlying issue and is no longer needed.
Show a summary per file
File Description
actions/setup/js/vitest.config.mjs Removes forceExit from vitest config now that the hang cause is addressed.
actions/setup/js/safe_output_manifest.test.cjs Replaces the /proc/... test path with /dev/null/... to fail fast instead of hanging on Linux.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 0

@dsyme
Copy link
Copy Markdown
Collaborator Author

dsyme commented Apr 14, 2026

Prompt:

That bug was incredibly subtle and the hangs wasted a lot of team time. Is there really no vitest setting to make testing more robust against this sort of thing?

Result:

Yeah — many tests mutate process.env, so --no-file-parallelism is needed to prevent cross-contamination between files sharing the same worker. That's a valid reason to keep it.

Bottom line: vitest doesn't have a collection-phase timeout, and you legitimately need serial execution. The best defense is pragmatic:

  • Avoid proc, sys, and other virtual filesystems in test paths — they can block indefinitely on mkdir, stat, or readdir with { recursive: true }
  • The CI timeout-minutes: 20 is the safety net, but by then you've already wasted 20 minutes
  • A lint rule or grep in CI checking for proc or sys in test files would catch this class of bug early:
    grep -rn '/proc/\|/sys/' actions/setup/js/*.test.cjs && echo "FAIL: test uses virtual filesystem path" && exit 1

There's no vitest knob that would have prevented this — it's a kernel-level block that freezes the Node.js process before vitest's timeout machinery is even involved.

@dsyme dsyme merged commit d1bdc96 into main Apr 14, 2026
55 checks passed
@dsyme dsyme deleted the fix/vitest-hang-proc-mkdir branch April 14, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants