feat(rpc, openapi): improve malformed response handling in RPCLink and OpenAPILink - #1836
Conversation
…APILink Replace the bare MALFORMED_ORPC_ERROR_RESPONSE error with a general MALFORMED_ORPC_RESPONSE ORPCError created via a shared createORPCErrorFromMalformedResponse helper: - message is inferred from the body (string or body.message) or from the common error code matching the status - cause is a new MalformedResponseError carrying the typed resolved response, so users can reliably identify malformed responses like validation errors - deserialization failures (Invalid RPC/OpenAPI response format) produce the same error with the raw resolved body attached - OpenAPILinkCodec resolves the body outside try/catch, matching RPCLinkCodec, so body-read failures propagate the original error Document the behavior in the RPCLink and OpenAPILink docs.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
More templates
@orpc/ai-sdk
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/experimental-effect
@orpc/evlog
@orpc/hibernation
@orpc/json-schema
@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! |
There was a problem hiding this comment.
ℹ️ Minor suggestions only. The malformed-response handling is well structured and well tested — two small rough edges inline.
Reviewed changes — Read the full PR diff (1 commit, 9 files). It consolidates malformed-response handling behind a shared createORPCErrorFromMalformedResponse helper and a new MalformedResponseError cause, rewires both RPCLinkCodec and OpenAPILinkCodec to surface a MALFORMED_ORPC_RESPONSE ORPCError (renamed from MALFORMED_ORPC_ERROR_RESPONSE, which no longer exists anywhere in the repo) with the raw resolved body attached, makes OpenAPI body-read failures propagate the original resolveBody error, and adds doc sections plus tests. New exports are properly re-exported from @orpc/client, and the cause/data/message-inference paths are all covered by assertions that would fail without the change.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
…/server roots Move the Standard* type re-exports (StandardResponse, StandardBody, etc.) from the /standard adapter entries to the package roots, so types used by root-level APIs like MalformedResponseError are importable from the same entry point.
- override name so instances report 'MalformedResponseError' in logs - only infer the message from body strings within reasonable length bounds; oversized bodies fall back to the status-derived message while remaining fully available on cause.response.body
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Re-reviewed commit efd51bd (delta since the prior Pullfrog review of daf27cee). Both points from the last review are cleanly addressed, and no new issues were introduced.
- Capped inferred error messages:
inferMalformedResponseMessagenow only uses a body string orbody.messagewhen its length is between 1 and 256 characters, otherwise falling back to the status-derived/common-code message — preventing huge HTML-error pages or long plain-text banners from becoming theORPCError.message(error-utils.ts). Regression tests cover the oversized string, oversizedmessage, and the general fallback path. - Set
nameonMalformedResponseError:override readonly name = 'MalformedResponseError'soerror.cause.namereads correctly in logs and stack traces (error.ts), with a test asserting it.
Both prior review threads are resolved.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Malformed responses, such as a proxy or gateway answering instead of the handler, now surface as an identifiable
MALFORMED_ORPC_RESPONSEORPCErrorwith a meaningful message instead of a generic one. Itscauseis a newMalformedResponseErrorcarrying the typed resolved response, so users can detect this case the same way they detect validation errors.Changes
body.message) or from the common error code matching the status; the previous behavior always used the generic default message.createORPCErrorFromMalformedResponse(options)helper in@orpc/clientnow backs bothRPCLinkCodecandOpenAPILinkCodec, accepting the same options shape asMalformedResponseError.Invalid RPC response format./Invalid OpenAPI response format.) throw the same error with the raw resolved body attached, so the actual server payload is no longer lost (the RPC deserializer turns unknown JSON intoundefined).OpenAPILinkCodecresolves the body outside try/catch likeRPCLinkCodec, so body-read failures propagate the original error instead of theCannot parse response bodywrapper.Breaking
MALFORMED_ORPC_ERROR_RESPONSEis renamed toMALFORMED_ORPC_RESPONSE, since it now also covers success responses that fail to deserialize.dataattached to the error is now the raw resolved body rather than the RPC/OpenAPI-deserialized value.Testing
type:check,lint, anddocs:validate.