Repository navigation
Conversation
Add `errorResponseContentType` to `OpenAPIHandler` and `OpenAPIGenerator.generate()`, e.g. `application/problem+json` for RFC 9457 Problem Details. The generator documents error responses under the configured media type. The handler codec sets the `content-type` header on error responses; it reaches the wire once `@standard-server` preserves a provided content type for JSON bodies. Refs #2317 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012JepnhdVCkPJwexoiHyqRR
… changes With `errorResponseContentType` set, the handler sends the error body as a JSON Blob of that type, since standard-server always sends plain JSON bodies as `application/json`. `OpenAPILink` gets the matching option and parses error responses with that content type as JSON. Refs #2317 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012JepnhdVCkPJwexoiHyqRR
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
orpc | 61bf41d | Commit Preview URL Branch Preview URL |
Oct 25 2026, 03:56 AM |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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: |
Merging this PR will not alter performance1 warning
Comparing Footnotes
|
There was a problem hiding this comment.
ℹ️ One minor interoperability suggestion inline — nothing blocking.
Reviewed changes
- Handler encoding —
encodeErrorwraps the serialized error body in aBlobtyped aserrorResponseContentTypewhen set, relying on@standard-serverpreserving a Blob's own content type. - Link decoding — error responses whose
content-typematches the configured option are parsed withresolveBody('json'); everything else keeps usingresponseBodyHint. - Generator —
errorResponseContentTypeis threaded throughOpenAPIOperationContext(default'application/json') and applied only tobuildErrorResponse, so success bodies are untouched. - Tests / docs — unit, e2e and round-trip coverage for the handler, link and generator, plus handler/link/specification docs.
Verified locally: pnpm vitest run packages/openapi packages/nest (608 tests) and pnpm type:check both pass. I also confirmed the node/aws-lambda/fastify adapters preserve the Blob type verbatim (Fastify returns application/problem+json with no ; charset=utf-8 appended), so the custom media type survives the built-in adapters.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
| const body = await response.resolveBody(meta?.responseBodyHint) | ||
| const isCustomErrorContentType = !isOk | ||
| && this.errorResponseContentType !== undefined | ||
| && flattenStandardHeader(response.headers['content-type']) === this.errorResponseContentType |
There was a problem hiding this comment.
This compares the raw content-type header to the option with strict string equality, so a media type that carries parameters or different casing (application/problem+json; charset=utf-8, Application/Problem+JSON) won't match. Since OpenAPILink is documented to call any OpenAPI-compliant server, that mismatch would fall back to the header-derived hint — and because the handler sets standard-server: file, the body resolves as a File and decodeResponse throws MalformedResponseError on a valid JSON body.
Technical details
# Normalize the media type before comparing
## Affected sites
- `packages/openapi/src/adapters/standard/openapi-link-codec.ts:397` — `flattenStandardHeader(response.headers['content-type']) === this.errorResponseContentType`
## Required outcome
- A configured `errorResponseContentType` matches an error response whose `content-type` is the same media type, ignoring parameters and case (e.g. `application/problem+json` matches `application/problem+json; charset=utf-8`).
## Suggested approach
- Compare the normalized media type (split on `;`, trim, lowercase) rather than the raw header, mirroring `resolveStandardBodyHint` in `@standard-server/core`, which already does `?.split(';')[0]?.trim().toLowerCase()`.
## Open questions for the human
- Whether to be lenient here, given the handler and link are usually configured with identical strings in oRPC's own adapter stack.
Closes #2317
Adds an
errorResponseContentTypeoption toOpenAPIHandler,OpenAPILinkandOpenAPIGenerator.generate(). Use it to send and document errors under a different media type, such asapplication/problem+jsonfor RFC 9457 Problem Details.Changes
encodeErrorsends the JSON error body as aBlobof that type.@standard-serveralways sends plain JSON bodies asapplication/json, but it keeps a Blob's own type, so no@standard-serverchange is needed. Because of this, these responses also carrystandard-server: file,content-disposition: inline; filename="blob"andcontent-lengthheaders.content-typeequals the option is read withresolveBody('json'). All other responses still useresponseBodyHint. A non-JSON error page from a proxy therefore still gives aMalformedResponseError.application/json.Without the option, nothing changes.
Tests
'json'only on error responses with a matching type).OpenAPIHandlerandOpenAPILink: the response is sent asapplication/problem+json, and the client throws the matchingORPCError.pnpm vitest run packages/openapi packages/nest,tsc,@orpc/nesttype check, lint andpnpm docs:validateall pass.Generated by Claude Code