fix: fallback to structured-clone for RPC error envelopes#8
Merged
Conversation
✅ Deploy Preview for devfra ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR fixes a WS RPC transport regression where jsonSerializable: true methods could crash the strict JSON serializer when the handler throws (because the error envelope contains a thrown value like an Error). It routes error envelopes through the structured-clone wire format instead, allowing the original failure to propagate to the caller.
Changes:
- Update WS server transport serialization to bypass strict JSON for error envelopes (
{ t: 's', i, e }) and use structured-clone instead. - Update WS client transport serialization with the same error-envelope structured-clone fallback behavior.
- Add a regression test ensuring a thrown error results in a rejection rather than a DF0020 serialization crash.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/devframe/src/rpc/transports/ws-server.ts | Avoids strict JSON encoding for error responses so thrown values don’t crash serialization. |
| packages/devframe/src/rpc/transports/ws-client.ts | Mirrors server behavior to ensure error envelopes use structured-clone instead of strict JSON. |
| packages/devframe/src/rpc/transports/ws.test.ts | Adds regression coverage for thrown errors in jsonSerializable: true RPC methods over WS. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+75
to
+79
| const { wss } = attachWsRpcTransport(server, { port: PORT, host: HOST, definitions: definitions as any }) | ||
|
|
||
| try { | ||
| const client = createRpcClient<typeof serverFunctions, Record<string, never>>({}, { | ||
| channel: createWsRpcChannel({ url: WS_URL, definitions: definitions as any }), |
Comment on lines
+60
to
+63
| const PORT = 3334 | ||
| const HOST = '127.0.0.1' | ||
| const WS_URL = `ws://${HOST}:${PORT}` | ||
|
|
- Drop unnecessary `as any` casts on `definitions` — the local map type is structurally compatible with the transport's expected shape. - Allocate the port via `get-port-please` instead of hardcoding `3334`, matching the pattern in `adapters/__tests__/dev.test.ts` and avoiding flakes when the port is already in use.
Extends the structured-clone error fallback shipped for the WS RPC
transport to the dump and MCP surfaces:
- Dumps capture `Error.cause` chains and own properties instead of
reducing to `{ message, name }`. Static-dump promotes error-bearing
records to structured-clone per-record (via new
`recordSerializations`/`fallbackSerialization` manifest fields) so
`jsonSerializable: true` functions still round-trip thrown errors
losslessly.
- MCP replaces the bare `JSON.stringify` with a coercing helper for
`BigInt`/`Date`/`Map`/`Set`/`Error`/cycles, since MCP wire format is
text-only and cannot use the `s:` structured-clone prefix. Error
responses now include `name` and `cause.message`.
`serializeDumpError` already flattens the common rich-error shape (`message`, `name`, recursive `cause`) into a JSON-safe object, so `jsonSerializable: true` functions that throw ordinary errors round-trip through strict JSON without any per-record promotion. The edge case — an error with non-JSON own properties (e.g. a `Map` attached to the thrown error) — now surfaces as `DF0020` at build time, consistent with the rest of the `jsonSerializable: true` contract.
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.
This PR came from vitejs/devtools#336.
Description
jsonSerializable: truedeclares the result shape of an RPC function, but the WS transport appliedstrictJsonStringifyto every outgoing message routed to such a method — including the error envelope ({ t: 's', i, e }) emitted when the handler throws. BecauseErrorinstances aren't JSON-serializable, this crashed the serializer with DF0020 and masked the original DTK0011 entirely, taking the dev server down with it (reproducible on StackBlitz / WebContainer).Skip the strict-JSON path for error envelopes on both ws-server and ws-client transports so thrown values round-trip via structured-clone, and the underlying failure surfaces on the caller instead.
Linked Issues
close: vitejs/devtools#335
Additional context
N/A