Repository navigation
fix(rpc): skip unknown meta types when deserializing - #2357
Conversation
Client and server can run different versions with different serializer handlers. Previously a meta entry with a handler key the receiver did not know threw and failed the whole payload. Now such entries are skipped, so the value stays in its serialized form while known values, including those nested inside it, are still restored. Skipped entries neither walk nor mutate the payload, and types are still looked up on a null-prototype map, so prototype keys never resolve to a handler. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VVaw7RZzFyYdaijHa8YrMn
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Skip unknown meta types on deserialize —
deserializeJsonnowcontinues past a meta entry whose type has no handler instead of throwing, so a client and server with different handler sets can still exchange payloads. - Null-prototype lookup preserved —
__proto__/constructor/toStringstill resolve toundefinedand are now skipped rather than rejected, keeping the prototype-pollution guard intact. - Tests — added an
unknown typesblock covering serialized-form retention and nested-value restoration; the security prototype-chainit.eachnow asserts the value is returned unchanged; removed the redundant throw test inrpc-serializer.test.ts. - Docs —
:::info[Handlers out of sync]note inrpc/serializer.mdxand a JSDoc line onhandlers.
I traced the skipped path through the chain / chainDepth prefix-reuse optimization: skipped entries neither walk nor mutate, and since the chain is only updated by processed entries, later entries that share a prefix reuse it exactly as before. The new tests cover both sibling and nested cases. The PR body already documents the one real trade-off (a mismatch is now silent, with no strict-mode escape hatch), which is a deliberate maintainer call, so nothing to flag inline.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
orpc | 660f958 | Commit Preview URL Branch Preview URL |
Oct 29 2026, 10:05 AM |
More templates
@orpc/ai-sdk
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/effect
@orpc/evlog
@orpc/hibernation
@orpc/json-schema
@orpc/experimental-lock
@orpc/mcp
@orpc/msw
@orpc/nest
@orpc/next
@orpc/node
@orpc/openapi
@orpc/opentelemetry
@orpc/pinia-colada
@orpc/pino
@orpc/publisher
@orpc/ratelimit
@orpc/server
@orpc/shared
@orpc/swr
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/zod
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merging this PR will not alter performance1 warning
Comparing Footnotes
|

Summary
Client and server code can't always be deployed in sync, so one side may receive a
metaentry whose handler key it doesn't have (a custom handler added on one side only, or a built-in disabled withhandlers: { url: undefined }).RPCJsonSerializer.deserializeJsonused to throwtype "X" is not supported., failing the whole payload.Unknown types are now skipped: the value stays in its serialized JSON form, and everything else in the payload, including known values nested inside the unknown one, is still restored.
__proto__,constructor,toString, etc. never resolve to a handler; they're just skipped now.Trade-off
A mismatch is now silent. On the server, a value left in serialized form reaches input validation, which will usually reject it (e.g. a string where a
Dateis expected). On the client there is no such check, so the caller gets the serialized form. There's no option to restore the strict behaviour; happy to add one if wanted.Changes
packages/client/src/rpc-json-serializer.ts: skip unknown types instead of throwing; note the behaviour in thehandlersJSDoc.rpcJsonSerializer: unknown typesblock, and the prototype-chain tests now expect the value back unchanged (dropped the duplicate inrpc-serializer.test.ts).apps/content/docs/rpc/serializer.mdx: "Handlers out of sync" note.Testing
packages/clientandtests/rpcsuites,tsc,eslint, anddocs:validatepass locally.Generated by Claude Code