$ the-wire · showcase
Undici stops HTTP/2 pool fan-out, Node's TLS state machine gets re-entrancy guards
By RepoJournal · Filed · About Node.js · Composed from the cited sources · methodology
Undici now queues concurrent requests behind a single protocol probe while an HTTP/2-capable client negotiates TLS/ALPN, and Node's TLS layer defers re-entrant calls that could corrupt the OpenSSL/BoringSSL state machine.
Undici's Pool no longer fans out connections during ALPN negotiation [1]. Concurrent requests used to open fresh connections while the client was still probing for HTTP/2; they now stay queued behind one probe, multiplex over HTTP/2 once negotiation completes, and fall back to normal HTTP/1.1 connection fan-out when HTTP/1.1 wins. The change also covers repeated cold bursts after idle session reaping and preserves HTTP/1.1 concurrency, with the Agent and Pool documentation updated to match.
Node's TLS internals gained a guard against re-entrant calls into the SSL state machine [2], wrapping each call into OpenSSL at the top level and checking that scope in DoWrite, DoShutdown, and Cycle when they are triggered from JS. The stated goal is making sure the OpenSSL/BoringSSL state machine is never manipulated from inside itself, described as a step toward that issue.
In the FFI paths, GetValidatedPointerAddress() and GetValidatedSize() now throw ERR_INVALID_ARG_TYPE instead of ERR_INVALID_ARG_VALUE when a pointer or size argument is the wrong type [3]. The distinction matters: ERR_INVALID_ARG_VALUE is reserved for a right-typed but unsupported value, matching what the JavaScript validators behind exportString() and exportBuffer() already throw.
Amaro adopted binding_nodejs_support_wasm [4], part of a plan to make all of Node.js's internal AST parsing Amaro-based and remove the dependency on slower JavaScript-based parsers. Two smaller fixes landed alongside: zstd reset now preserves dictionaries and params plus missing documentation [5], and the flaky common WPT inspector test now waits for the WPT child to reach its startup wait before sending Runtime.runIfWaitingForDebugger [6]. The VFS ZipProvider now treats archive entry prefixes as directories when renaming, moving all descendant entries to the new prefix in both async and sync operations [7].
Action items
- → Upgrade undici to a release containing the ALPN pool fan-out fix if you run HTTP/2-capable clients under load nodejs/undici [plan]
- → Audit FFI error handling for code that catches ERR_INVALID_ARG_VALUE on pointer or size arguments; it is now ERR_INVALID_ARG_TYPE nodejs/node [plan]
- → Monitor the zstd reset fix if you rely on dictionaries or params surviving a zlib stream reset nodejs/node [monitor]
References
- [1] fix(h2): avoid pool fan-out during ALPN negotiation ↗ nodejs/undici
- [2] tls: defer re-entrant calls to SSL state machine from JS ↗ nodejs/node
- [3] ffi: throw ERR_INVALID_ARG_TYPE for wrong-typed pointer and size ↗ nodejs/node
- [4] feat: use `binding_nodejs_support_wasm` ↗ nodejs/amaro
- [5] zlib: fix zstd reset ↗ nodejs/node
- [6] test: fix flaky common WPT inspector test ↗ nodejs/node
- [7] vfs: support renaming implicit ZIP directories ↗ nodejs/node