Skip to content

feat!: remove typesafe returned errors and the inferable flag - #1987

Merged
dinwwwh merged 3 commits into
middleapi:mainfrom
dinwwwh:claude/github-discussion-1982-c9762d
Sep 7, 2026
Merged

feat!: remove typesafe returned errors and the inferable flag#1987
dinwwwh merged 3 commits into
middleapi:mainfrom
dinwwwh:claude/github-discussion-1982-c9762d

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 6, 2026

Copy link
Copy Markdown
Member

Handlers can no longer signal an error by returning an ORPCError. What a handler returns is its output, what it throws is an error, and .errors or the error() factory is the only way to get a typesafe error. With returned errors gone the inferable flag always equalled defined, so it is removed and isInferableError goes back to its v1 name isDefinedError.

Implements the proposal in #1982.

Breaking changes

  • A returned ORPCError is plain output. Under an output schema it is a type error.
  • Procedure, DecoratedProcedure, ProcedureClient, ProcedureClientOptions, CallOptions and the Next.js server function types lose their trailing TReturnedError generic. opaqueReturnedErrors is gone from the procedure definition.
  • ORPCError and ORPCErrorJSON no longer carry inferable. The error response body and generated OpenAPI error schemas drop the field, so clients on this build reject error bodies from earlier v2 betas that still send it.
  • isInferableError is renamed to isDefinedError with no alias, and safe exposes definedError instead of inferableError.
  • Effect: an ORPCError that fails the effect is thrown as-is instead of becoming an inferable error.

Performance

  • No instanceof check or error clone on the handler output path.
  • One less generic on every procedure and client type, and .handler no longer splits its return type with Exclude/Extract.

Docs

  • Removed the "Returning an ORPCError" section, rewrote the Effect typesafe-errors section around .errors, renamed the client error-handling anchor to #using-safe-and-isdefinederror, and updated the v1 migration guide, RPC protocol example, Next.js docs, skills and playgrounds.

Testing

  • Root and per-package type checks, eslint and the JSDoc backlink checker pass.
  • Full vitest passes. Type tests now assert that a returned ORPCError is output and is rejected under an output schema.

Handlers can no longer signal an error by returning an ORPCError; a
returned ORPCError is plain output. The TReturnedError generic, the
opaqueReturnedErrors flag and the handler output check are removed.

With returned errors gone, inferable always equalled defined, so the
field is dropped from ORPCError, its JSON body and the OpenAPI error
schemas. isInferableError is renamed back to isDefinedError and the
safe result exposes definedError.

Implements middleapi#1982
@codecov

codecov Bot commented Sep 6, 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 Sep 6, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will improve performance by 13.23%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 2 improved benchmarks
✅ 28 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
plain 163.8 µs 140.8 µs +16.35%
validated 77.5 µs 70.3 µs +10.2%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing dinwwwh:claude/github-discussion-1982-c9762d (859c26b) with main (e99ad16)

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 critical issues — the refactor is thorough and verifiably green; one stale doc reference is noted in the nitpicks below.

Reviewed changes — PR #1987 removes typesafe returned errors and the inferable flag: a returned ORPCError is now plain output (a type error under an output schema), the TReturnedError generic and opaqueReturnedErrors are gone from Procedure/ProcedureClient/CallOptions/Next server-function types, ORPCError/ORPCErrorJSON/error bodies/OpenAPI error schemas drop inferable, and isInferableError/safe(...).inferableError are renamed to isDefinedError/definedError with no alias.

  • Rename to isDefinedError + definedErrorisInferableErrorisDefinedError (now gates on error.defined), and the safe result's third element inferableErrordefinedError, thread through every package, docs page, skill, playground, and type test.
  • Returned errors are now outputexecuteProcedureInternal no longer intercepts/clones returned ORPCErrors, and builder .handler types drop the | AnyORPCError union; type tests pin both directions (plain output without an output schema, rejected with one).
  • Wire/OpenAPI format change — error JSON bodies and generated error schemas drop inferable; isORPCErrorJson now rejects legacy bodies that still carry it, and the msw e2e suites confirm the defined flag round-trips over both RPC and OpenAPI transports.
  • Effect integrationhandlerGen drops succeedOnORPCError, so a failed ORPCError throws as-is; tests assert failed-vs-returned ORPCErrors resolve to error vs. output respectively, and the docs steer .errors + errors.X() + Effect.fail.
  • Docs/skills/migration guide — the "Returning an ORPCError" section is removed, the client anchor is now #using-safe-and-isdefinederror, the from-v1 rename table and the isDefinedError/isInferableError migration note are cleaned up, and all recipes/skills are updated.

I verified the branch locally: full workspace tsc -b passes (including every *.test-d.ts), all affected-package vitest suites pass (client/contract/server/effect, openapi/next/trpc/msw/tanstack-query/pinia-colada/swr/ai-sdk — 202 files / 2005 tests), the root tests/ e2e suite passes (465 tests), eslint on the touched files is clean, and the JSDoc backlink checker reports 0 errors/0 warnings. Repo-wide greps confirm no isInferableError, inferableError, inferable (beyond a prose comment in client/src/error.ts), TReturnedError, or opaqueReturnedErrors remains anywhere in runtime code, docs, or tooling.

ℹ️ Nitpicks

  • packages/client/src/client-safe.ts:20-21 — the createSafeClient JSDoc example still destructures inferrableError (the old property name, with a long-standing extra r), but the safe result's third element is now definedError. Anyone copying this snippet lands on a property that no longer exists; the safe JSDoc in utils.ts was updated but this spot was missed.

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

@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 — one commit since the prior review, addressing the previous run's only nitpick.

  • Fixed the createSafeClient JSDoc example in packages/client/src/client-safe.tsinferrableError is now definedError, matching the real third element of the safe result (SafeResult in client/src/utils.ts). Confirmed accurate against the type and consistent with the safe JSDoc.

No further issues; the remaining delta is a docs-only comment change with no behavioral surface.

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

@pkg-pr-new

pkg-pr-new Bot commented Sep 6, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

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

@orpc/arktype

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

@orpc/bun

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

@orpc/client

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

@orpc/cloudflare

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

@orpc/contract

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

@orpc/experimental-effect

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

@orpc/evlog

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

@orpc/hibernation

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

@orpc/json-schema

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

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@1987

@orpc/nest

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

@orpc/next

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

@orpc/node

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

@orpc/openapi

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

@orpc/opentelemetry

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

@orpc/pinia-colada

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

@orpc/pino

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

@orpc/publisher

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

@orpc/ratelimit

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

@orpc/server

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

@orpc/shared

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

@orpc/swr

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

@orpc/tanstack-query

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

@orpc/trpc

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

@orpc/valibot

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

@orpc/zod

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

commit: 859c26b

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

I tested 7899e79 against a copy of my app using contract-first oRPC, Effect 4.0.0-rc.112, and React/Svelte clients.

All 130 API tests pass on both beta.33 and this preview. The API and both frontends also typecheck. The integration checks use the actual routes, Effect middleware, error mapping, and OpenAPI client; session and data services are mocked.

Auth rejection, typed business errors, 503/500 responses, and Date coercion behaved as expected. Existing client code using isDefinedError continues to work.

I also confirmed the documented mixed-version incompatibility in both directions: DUPLICATE_BOOKMARK becomes MALFORMED_ORPC_RESPONSE when only one side is upgraded. Matching versions preserve the code and data.

No regressions found in these paths.

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

Important

The latest commit deletes every test that pins this PR's headline behavior — a returned ORPCError is plain output and is rejected under an output schema — while the PR description still claims those type tests exist ("Type tests now assert that a returned ORPCError is output and is rejected under an output schema"). I restored all the deleted tests against the current head and every one passes, so this is a coverage regression, not a fix for failing tests.

Reviewed changes — one commit since the prior pullfrog review (859c26b, "test: remove returned ORPCError cases"), which deletes 205 lines of tests across six files.

  • Deleted the returned-ORPCError type tests — the "treats returned ORPCError as output" assertions in builder.test-d.ts and builder-variants.test-d.ts, and the "does not allow returning ORPCError" @ts-expect-error cases in builder-variants.test-d.ts, implementer-procedure.test-d.ts, and effect.test-d.ts.
  • Deleted the returned-ORPCError runtime testseffect/handler.test.ts and server/procedure-client.test.ts, which asserted the error resolves as plain output with defined === false and no reconcile/clone.

⚠️ All tests pinning the PR's headline behavior were deleted

This commit removes the only coverage that verifies the core breaking behavior this PR ships: that a returned ORPCError is plain output (widening the output schema to Schema<'out' | ORPCError<'BAD_REQUEST', string>>) and that returning one under an output schema is a compile-time error. I restored every deleted test on the current head — server and effect tsc -b pass with the type tests restored, and vitest passes with the runtime tests restored — so none of them were failing; the coverage was dropped while the PR body still claims it exists. Either the tests should be restored, or the Testing section of the PR description should be corrected to match reality.

Technical details
# Deleted returned-ORPCError test coverage

## Affected sites
- packages/server/src/builder.test-d.ts — removed `treats returned ORPCError as output`
- packages/server/src/builder-variants.test-d.ts — removed 2× `treats returned ORPCError as output` + 2× `does not allow returning ORPCError`
- packages/server/src/implementer-procedure.test-d.ts — removed `does not allow returning ORPCError`
- packages/effect/src/extensions/effect.test-d.ts — removed 3× `treats returned ORPCError as output...` + 2× `does not allow returning ORPCError`
- packages/effect/src/handler.test.ts — removed `treats returned ORPCError as a regular output`
- packages/server/src/procedure-client.test.ts — removed `treats returned ORPCError as a regular output`

## Required outcome
- Restore the deleted tests (all pass against the current implementation), or
- If the removal is deliberate, update the PR body's Testing section, which currently claims these type tests exist.

## Verification performed
- Restored all six removed test groups on head `859c26b`; `pnpm --filter @orpc/server type:check`, `pnpm --filter @orpc/effect type:check`, and `pnpm vitest run packages/effect/src/handler.test.ts packages/server/src/procedure-client.test.ts` are all green.

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

@dinwwwh
dinwwwh merged commit a6366d9 into middleapi:main Sep 7, 2026
11 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.

2 participants