Repository navigation
fix(host): guard the bundled undici write path against setTypeOfService EINVAL - #824
Open
eatmoreduck wants to merge 1 commit into
Open
eatmoreduck wants to merge 1 commit into
eatmoreduck wants to merge 1 commit into
Conversation
…ce EINVAL Node 24's bundled undici (7.29.x) calls socket.setTypeOfService on every HTTP/1.1 request write with no try/catch. A connection reset in the window between connect and the first write makes macOS setsockopt(IP_TOS) answer EINVAL, the synchronous throw escapes as an uncaught exception, and the Harness host dies — entering the plugin market fires enough requests to hit it (dataelement#821). Upstream fixed by ignoring type-of-service errors (undici#5547, 7.x backport undici#6076), but no Node 24 release ships the backport yet. The harness node entry now wraps Socket.prototype.setTypeOfService before the DSH entry loads — same reach as the windowsHide enforcement in that file: every fetch in the process tree is covered without an upstream fix in each caller. EINVAL is swallowed with a one-time diagnostic; other errors still surface. The guard self-disables once the bundled runtime reports undici >= 7.30.1, so it disappears with the runtime bump.
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.
Motivation
Fixes #821.
Node 24's bundled undici (7.29.x) calls
socket.setTypeOfServiceon every HTTP/1.1 request write with no try/catch. When a connection is reset in the window between connect and the first write, macOSsetsockopt(IP_TOS)answersEINVAL, the synchronous throw escapes as an uncaught exception, and the Harness host dies — the reporter's crash logs show exactly this stack, and entering the plugin market fires enough requests to hit the reset window. Upstream fixed it by ignoring type-of-service errors (undici#5547, 7.x backport undici#6076), but the backport merged 2026-10-27 and no Node 24 release ships it yet, so the bundled Node 24.21.0 runtime cannot avoid it by configuration.Description
build/type-of-service-guard.mjs: wrapsSocket.prototype.setTypeOfService, swallows exactlyEINVALwith a one-time[harness-node]diagnostic, rethrows everything else. Installs only when the runtime reportsprocess.versions.undiciolder than 7.30.1, so the guard self-disables with the runtime bump and needs no removal PR.build/harness-node-entry.mjsinstalls the guard before the DSH entry loads — same reach as the existingwindowsHideenforcement in that file: every fetch in the host process tree (Harness internals, dshmarket, plugins) is covered without an upstream fix in each caller.test/harness-node-entry.test.ts: EINVAL swallowed + warned once, non-EINVAL rethrown, no install on undici ≥ 7.30.1 (or 8.x), no install when the runtime lacks the API (Node ≤ 22 — also verifies the realnode:netprototype is untouched on this dev runner).Type-of-service 0 is semantically a no-op, and the upstream fix ignores TOS errors entirely, so swallowing EINVAL loses nothing on the wire.
Validation
npx vitest run test/harness-node-entry.test.ts: 34/34 pass.npx vitest run test/: 2,696 passed / 39 failed — the 39 failures are the pre-existing office/ppt/docx.mjsset that fails identically on a cleanmaincheckout in this environment (dev install ran with--ignore-scripts;npx patch-packageapplied before the run).npm run typecheck: clean.The platform-level EINVAL cannot be reproduced on this dev machine (its Node 22 predates
setTypeOfService); the wrapper behavior is pinned by the contract tests, and the crash stack in #821 plus upstream undici#5544 carry the platform evidence.AI Disclosure
Made by an AI coding agent (GLM coding agent, Zhipu), human-supervised.