Skip to content

fix(client): stop WebSocket errors from crashing the process in RPCLink - #2111

Merged
dinwwwh merged 1 commit into
middleapi:mainfrom
dinwwwh:claude/jolly-khorana-46aee6
Sep 28, 2026
Merged

dinwwwh merged 1 commit into
middleapi:mainfrom
dinwwwh:claude/jolly-khorana-46aee6

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 28, 2026

Copy link
Copy Markdown
Member

A client using the WebSocket RPCLink with Node's ws library no longer crashes when the socket emits error. ws throws when error has no listener, and the link transport only listened for open, message and close, so a refused connection or a malformed frame from the server took the whole client process down. The transport now absorbs error, and the close event that always follows rejects pending calls or drives reconnection. This is the client-side counterpart to #2108.

Fixes

  • A refused connection rejects the call with WebSocket closed (code 1006: ) instead of crashing and leaving the call hanging.
  • With reconnect enabled, refused attempts while the server is down go through the normal retry path (including maxAttempt and proactive onClose reconnects) instead of crashing on every attempt.
  • A malformed frame from the server rejects pending calls instead of throwing an uncaught RangeError.
  • Browser, Deno, Bun and Cloudflare sockets behave as before.

Testing

  • New regression tests with a real ws server and client cover a refused connection, reconnecting after one, and a malformed server frame. Run alone without the fix, each exits 1 on the uncaught error.
  • ws and @types/ws are now devDependencies of @orpc/client.

`ws` throws when an `error` event has no listener, and the WebSocket
link transport only listened for `open`, `message` and `close`. A refused
connection (including every reconnect attempt while the server is down)
or a malformed frame from the server crashed the client process. The
transport now absorbs `error`; the `close` event that always follows
rejects pending calls or drives the reconnect path.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes

  • Absorb WebSocket error events — WebSocketLinkTransport now registers a no-op error listener so EventEmitter-based sockets like ws don't throw an uncaught error and crash the process; the close event that follows rejects pending calls or drives reconnection (packages/client/src/adapters/websocket/transport.ts:238).
  • Regression tests against a real ws server/client — cover a refused connection rejecting with WebSocket closed (code 1006: ), a refused-then-recovered attempt reconnecting with maxAttempt semantics, and a malformed server frame (0xC1 0x00, RSV1 set) rejecting pending calls (packages/client/src/adapters/websocket/rpc-link.test.ts).
  • ws / @types/ws devDependencies — added to @orpc/client for those tests (packages/client/package.json).

I verified the tests fail without the fix (2 of 3 with ws tests error on uncaught ECONNREFUSED / RangeError: Invalid WebSocket frame: RSV1 must be clear), that pnpm --filter @orpc/client type:check and the 27-test file pass, and that ws@8.21.3's client error paths (receiverOnError, senderOnError) always drive the socket toward close, so settling through close is sound. No action needed.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@codecov

codecov Bot commented Sep 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pkg-pr-new

pkg-pr-new Bot commented Sep 28, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@2111

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@2111

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@2111

@orpc/client

npm i https://pkg.pr.new/@orpc/client@2111

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@2111

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@2111

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@2111

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@2111

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@2111

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@2111

@orpc/experimental-lock

npm i https://pkg.pr.new/@orpc/experimental-lock@2111

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@2111

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@2111

@orpc/next

npm i https://pkg.pr.new/@orpc/next@2111

@orpc/node

npm i https://pkg.pr.new/@orpc/node@2111

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@2111

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@2111

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@2111

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@2111

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@2111

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@2111

@orpc/server

npm i https://pkg.pr.new/@orpc/server@2111

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@2111

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@2111

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@2111

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@2111

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@2111

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@2111

commit: 42afd0e

@codspeed

codspeed Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing dinwwwh:claude/jolly-khorana-46aee6 (42afd0e) with main (dfa4e1e)

Open in CodSpeed

@dinwwwh
dinwwwh merged commit 2f1100a into middleapi:main Sep 28, 2026
11 checks passed
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.

1 participant