Skip to content

undici request() and ws server both throw 'Cannot read properties of undefined' at the transport layer despite compiling cleanly #10797

Description

@proggeramlug

Two HTTP/WebSocket packages compile from real source but fail at runtime, both before any network I/O completes. Filing together because both are transport-layer failures found in the same probe and may share a cause; split if they diverge.

Found on origin/main (v0.5.1617), --profile perry-dev, Linux x64, versions pinned to each binding's [bindings.<pkg>.upstream] block.

undici 8.9.0 — 112 modules, compiles, then throws before connecting

TypeError: Cannot read properties of undefined (reading 'length')

Thrown from request() before any TCP connect is attempted, so it is not a socket or protocol problem — something is undefined in the request-construction path.

ws 8.21.1 — handshake provably correct, crash immediately after

TypeError: Cannot read properties of undefined (reading 'destroy')

This one is unusually well-localised by the probe: the WebSocket handshake is byte-exact, with a correct RFC 6455 Sec-WebSocket-Accept value computed and sent. The server then crashes before the 'connection' event fires. So the protocol logic works and the failure is in what happens to the socket object immediately afterwards — something that should be a socket is undefined at the point .destroy() is called on it.

Why these are worth taking together

Both are Cannot read properties of undefined on an object that the package expects the runtime to have provided — a socket in ws's case, something in the request path for undici. Both packages sit directly on node:net/node:http internals rather than on the public surface. If Perry is under-populating an object that Node provides, one fix may resolve both. If they turn out to be unrelated, this should be split into two issues.

Reproduction

Both: install the pinned version, add a perry.compilePackages entry, and exercise the primary documented use — request() against a local server for undici; a WebSocketServer plus a client connection for ws. Compare against node --experimental-strip-types on Node 26.5.1.

Note on how these were found

Both packages passed a static pre-screen for every known blocker shape (export = + namespace, conditional require, new Function with class expressions, bound-export native heritage, require.main). They failed anyway. That is the screen working as designed — it narrows where to look and predicts nothing about what it has not seen before — and it is why compiling is not optional before declaring a binding removable.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    package-auditFound by the 2026 package audit: compiling real npm packages from source instead of native bindings

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions