fix(client): forward error batch responses instead of parsing them - #1847
Conversation
A batch response with status >= 400 is not a batch payload, so decoding it always failed and every subrequest rejected with "Invalid batch response format." instead of the actual error. Forward the response to each subrequest so the codec can turn it into a proper ORPCError, sharing a single resolveBody() call so one-shot stream and blob bodies are not consumed twice.
|
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.
✅ No new issues found.
Reviewed changes — reviewed the full diff (2 files, 1 commit b97234dd) of fix(client): forward error batch responses instead of parsing them:
batch.ts: a new early branch inexecuteBatchforwards anystatus >= 400batch response as-is to every subrequest viamapSubresponse, wrapping the body inonce(...)so one-shot bodies aren't consumed twice.batch.test.ts: three new tests covering buffered + streaming forwarding, single body resolution, and a regression check thatstatus < 400batches still parse.
I traced the change end-to-end and it's correct: an error response now flows through the StandardLink codec exactly like a non-batched request, where RPCLinkCodec.decodeResponse (status < 400 = isOk) turns it into a proper ORPCError with the original status/headers/body — which is precisely the reported bug fix. The once wrapper shares one body resolution across subrequests, and ClientPeer.close() rejects the still-pending peer.request promises, which the outer suppressErrorFromCurrentBatch guard swallows — so there's no hang, unhandled rejection, or double-resolution. The new tests genuinely fail without the fix (a string body is not an array/Blob/stream, so the old path threw Invalid batch response format.), and all 31 batch tests pass locally.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

The batch link plugin tried to decode every batch response as a batch payload, including ones that clearly are not. A 404 on the batch endpoint, a 502 from a proxy, or an auth rejection all surfaced to every call in the batch as
Invalid batch response format., hiding the real status, headers, and body.Batch responses with status >= 400 are now forwarded to each subrequest as-is, so the codec turns them into a proper
ORPCErrorcarrying the original status and body.Fixes
Invalid batch response format.Testing
Forwarding is covered in both buffered and streaming modes, along with single body resolution and a regression check that successful batches still parse.
pnpm vitest run packages/client/src/plugins/batch.test.tspasses (31 tests), as dopnpm type:checkand lint.