Skip to content

fix(client): forward error batch responses instead of parsing them - #1847

Merged
dinwwwh merged 1 commit into
middleapi:mainfrom
dinwwwh:claude/batch-plugin-error-handling-4fc5ce
Aug 12, 2026
Merged

fix(client): forward error batch responses instead of parsing them#1847
dinwwwh merged 1 commit into
middleapi:mainfrom
dinwwwh:claude/batch-plugin-error-handling-4fc5ce

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Aug 12, 2026

Copy link
Copy Markdown
Member

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 ORPCError carrying the original status and body.

Fixes

  • Callers of a batched request now see the real error instead of Invalid batch response format.
  • The error body is resolved once and shared across subresponses, so one-shot stream and blob bodies are not consumed twice.
  • Responses with status < 400 decode as before.

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.ts passes (31 tests), as do pnpm type:check and lint.

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

vercel Bot commented Aug 12, 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 12, 2026 2:26am

@pkg-pr-new

pkg-pr-new Bot commented Aug 12, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

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

@orpc/arktype

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

@orpc/bun

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

@orpc/client

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

@orpc/cloudflare

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

@orpc/contract

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

@orpc/experimental-effect

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

@orpc/evlog

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

@orpc/hibernation

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

@orpc/json-schema

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

@orpc/nest

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

@orpc/next

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

@orpc/node

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

@orpc/openapi

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

@orpc/opentelemetry

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

@orpc/pinia-colada

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

@orpc/pino

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

@orpc/publisher

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

@orpc/ratelimit

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

@orpc/server

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

@orpc/shared

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

@orpc/swr

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

@orpc/tanstack-query

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

@orpc/trpc

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

@orpc/valibot

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

@orpc/zod

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

commit: b97234d

@codecov

codecov Bot commented Aug 12, 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 12, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing dinwwwh:claude/batch-plugin-error-handling-4fc5ce (b97234d) with main (29c4fbc)

Open in CodSpeed

@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 — 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 in executeBatch forwards any status >= 400 batch response as-is to every subrequest via mapSubresponse, wrapping the body in once(...) 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 that status < 400 batches 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.

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

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