Repository navigation
fix: delay process.exit on Windows to dodge libuv UV_HANDLE_CLOSING crash - #228
Merged
Merged
Conversation
…rash On Windows, the explicit process.exit() calls in run() abort with Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), file src\win\async.c, line 76 when the openai SDK's undici-based HTTP/2 connection pool is still tearing down the TLS socket to models.github.ai. This is the upstream Node bug tracked at nodejs/node#56645 — Node calls uv_async_send() on an async handle after uv_close(), which libuv asserts against. The upstream fix (nodejs/node#61999) has been stalled in review since January 2025, and no released Node version contains it yet. Reproduces 100% of the time against models.github.ai on Windows Node 24 with the openai SDK; passes 100% with a brief setTimeout before exit. Same workaround already shipped by astral-sh/setup-uv (#880, 100ms) and silverwind/updates (#138, 200ms). Extract a `safeExit(code)` helper that yields for 100ms on Windows only before calling process.exit; Linux and macOS take the original code path with no added latency. Refs: - nodejs/node#56645 - astral-sh/setup-uv#880 - silverwind/updates#138
mickey-mikey
force-pushed
the
fix/libuv-windows-exit
branch
from
May 24, 2026 06:12
4593b45 to
0bb3dae
Compare
Contributor
|
@mickey-mikey Thanks for putting up the PR. Happy to approve once licensed cache is updated and linting errors are fixed up. |
Regenerated via `licensed cache` to clear 22 out-of-date dependency records and 2 stale entries (@fastify/busboy, safe-buffer) flagged by the Licensed CI check. New entry: ip-address. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- VALIDATE_BIOME_FORMAT/LINT: false — Biome's defaults (tabs, double quotes, semicolons) conflict with the project's Prettier+ESLint toolchain. Follows the same one-toolchain-per-concern pattern as the existing VALIDATE_JAVASCRIPT_STANDARD/TYPESCRIPT_STANDARD disables. - dependabot.yml cooldown: 5 days — resolves the zizmor dependabot-cooldown warnings on both ecosystems. Trivy still reports transitive-dep CVEs (mostly hono/express subgraph); those need a focused dependency-update PR, not bundling into this fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Non-breaking transitive-dep updates (package.json unchanged). Reduces Trivy's reported CVE count from 18 to a smaller residual that requires `--force` and breaking changes. dist/ rebundled to pick up the patched deps. All 105 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@sgoedecke, I did what I can, but I think I might need some help. I'm getting errors that might require breaking changes from Trivy. Could you take a look? |
sgoedecke
approved these changes
May 25, 2026
Contributor
|
@mickey-mikey Thanks for trying. There are some CI issues here that I don't think we need to resolve as part of this PR. Approved, merged, cut a new release. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #227.
What
Extract a
safeExit(code)helper that yields 100ms on Windows before callingprocess.exit(code), and route both existingprocess.exitcalls through it. Behaviour on Linux and macOS is unchanged (no setTimeout in their code path).Why
The two explicit
process.exit()calls inrun()abort with the libuvUV_HANDLE_CLOSINGassertion on Windows when theopenaiSDK's undici-based HTTP/2 connection pool is still tearing down the TLS socket tomodels.github.ai. Documented upstream Node bug at nodejs/node#56645 (open since Jan 2025; the fix PR #61999 has been stalled in review and no released Node version contains it). See #227 for the full diagnosis and reproducer.The 100ms setTimeout is the same workaround already shipped by astral-sh/setup-uv#880, silverwind/updates#138 (200ms), dmno-dev/varlock#600, and others tracking the same Node issue.
Verification
Local repro on Windows (Node 24.15.0 bundled with actions-runner v2.334.0,
openaiSDK againstmodels.github.ai,process.exit(0)immediately after the call):Without the patch: 5/5 trials crashed with the UV_HANDLE_CLOSING assertion (exit
0xC0000409).With the patch: 5/5 trials passed.
End-to-end CI on a private repo across self-hosted Linux, macOS, and Windows runners (single run each):
actions/ai-inference@v2.1.0unpatched: Windows leg crashed at the ai-inference step; Linux and macOS passed.Fork pinned to this PR's commit: all three legs passed.
Notes
The helper is
asyncand returnsPromise<never>. Both existing call sites are already inasynccontext so callers becomeawait safeExit(...)instead ofprocess.exit(...).silverwind tried dropping the explicit
process.exit(let the event loop drain) in their #137 and rolled back to the setTimeout in #138 — the drain approach did not hold up on Node 24 Windows.100ms matches setup-uv's current value (originally 50ms in #689, raised to 100ms in #880). silverwind uses 200ms.