Skip to content

feat(rpc, openapi): improve malformed response handling in RPCLink and OpenAPILink - #1836

Merged
dinwwwh merged 3 commits into
middleapi:mainfrom
dinwwwh:claude/malformed-orpc-error-response-394ec4
Aug 11, 2026
Merged

feat(rpc, openapi): improve malformed response handling in RPCLink and OpenAPILink#1836
dinwwwh merged 3 commits into
middleapi:mainfrom
dinwwwh:claude/malformed-orpc-error-response-394ec4

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Aug 11, 2026

Copy link
Copy Markdown
Member

Malformed responses, such as a proxy or gateway answering instead of the handler, now surface as an identifiable MALFORMED_ORPC_RESPONSE ORPCError with a meaningful message instead of a generic one. Its cause is a new MalformedResponseError carrying the typed resolved response, so users can detect this case the same way they detect validation errors.

Changes

  • The error message is inferred from the response body (a string body, or a string body.message) or from the common error code matching the status; the previous behavior always used the generic default message.
  • A shared createORPCErrorFromMalformedResponse(options) helper in @orpc/client now backs both RPCLinkCodec and OpenAPILinkCodec, accepting the same options shape as MalformedResponseError.
  • Deserialization failures (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 into undefined).
  • OpenAPILinkCodec resolves the body outside try/catch like RPCLinkCodec, so body-read failures propagate the original error instead of the Cannot parse response body wrapper.
  • New "Malformed Responses" sections in the RPCLink and OpenAPILink docs show identifying the case from a link interceptor.

Breaking

  • The error code MALFORMED_ORPC_ERROR_RESPONSE is renamed to MALFORMED_ORPC_RESPONSE, since it now also covers success responses that fail to deserialize.
  • The data attached to the error is now the raw resolved body rather than the RPC/OpenAPI-deserialized value.

Testing

  • Unit tests cover every message-inference path, the cause identity, and both codecs' malformed paths; all 901 client + openapi tests pass, along with type:check, lint, and docs:validate.

…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.
@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
orpc Ready Ready Preview Aug 11, 2026 4:29am

@dinwwwh dinwwwh changed the title feat(client): improve malformed response handling in RPCLink and OpenAPILink feat(rpc, openapi): improve malformed response handling in RPCLink and OpenAPILink Aug 11, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 11, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

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

@orpc/arktype

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

@orpc/bun

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

@orpc/client

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

@orpc/cloudflare

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

@orpc/contract

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

@orpc/experimental-effect

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

@orpc/evlog

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

@orpc/hibernation

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

@orpc/json-schema

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

@orpc/nest

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

@orpc/next

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

@orpc/node

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

@orpc/openapi

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

@orpc/opentelemetry

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

@orpc/pinia-colada

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

@orpc/pino

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

@orpc/publisher

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

@orpc/ratelimit

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

@orpc/server

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

@orpc/shared

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

@orpc/swr

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

@orpc/tanstack-query

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

@orpc/trpc

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

@orpc/valibot

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

@orpc/zod

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

commit: efd51bd

@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing dinwwwh:claude/malformed-orpc-error-response-394ec4 (efd51bd) with main (70db448)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (77b2a40) during the generation of this report, so 70db448 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@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.

ℹ️ 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.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread packages/client/src/error.ts
Comment thread packages/client/src/error-utils.ts Outdated
…/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

@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 — 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: inferMalformedResponseMessage now only uses a body string or body.message when 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 the ORPCError.message (error-utils.ts). Regression tests cover the oversized string, oversized message, and the general fallback path.
  • Set name on MalformedResponseError: override readonly name = 'MalformedResponseError' so error.cause.name reads correctly in logs and stack traces (error.ts), with a test asserting it.

Both prior review threads are resolved.

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

@dinwwwh
dinwwwh merged commit b4c00e4 into middleapi:main Aug 11, 2026
12 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