Skip to content

Conversation

@unnoq
Copy link
Member

@unnoq unnoq commented Dec 10, 2025

Summary by CodeRabbit

  • New Features

    • Introduced the Rethrow Handler Plugin to allow selective rethrowing of errors to the host framework via a configurable filter.
  • Documentation

    • Added a documentation page for the plugin with usage examples.
    • Updated integration guides and site navigation to include the Rethrow Handler Plugin.
  • Tests

    • Added comprehensive tests covering rethrow behavior, filtering, context corruption cases, and normal operation.
  • Chores

    • Exposed the plugin in the public plugin exports.

✏️ Tip: You can customize this high-level summary in your review settings.

@unnoq unnoq requested a review from Copilot December 10, 2025 08:10
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Dec 10, 2025
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @unnoq, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new RethrowHandlerPlugin designed to give developers more control over error propagation within the server. It allows specific errors to be rethrown, bypassing the default oRPC error handling flow, which is particularly useful for integrating with existing framework-level exception handling systems like those found in NestJS or Express. This enhances flexibility and allows for a more unified error management strategy across an application.

Highlights

  • New Rethrow Handler Plugin: Introduced experimental_RethrowHandlerPlugin to provide flexible error handling capabilities within the server.
  • Selective Error Rethrowing: The plugin allows users to define a filter function to decide which errors should be rethrown, enabling seamless integration with external error handling mechanisms (e.g., NestJS exception filters).
  • Comprehensive Documentation: Detailed documentation for the new plugin has been added, including usage examples and its purpose.
  • Unit Tests: Thorough unit tests have been included to ensure the correct behavior of the RethrowHandlerPlugin under various error scenarios.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds an experimental RethrowHandlerPlugin that can selectively rethrow errors via a user-provided filter during request handling; includes implementation, tests, documentation, and docs navigation and example updates for Nest integration.

Changes

Cohort / File(s) Change Summary
Docs navigation
apps/content/.vitepress/config.ts
Added a sidebar/navigation entry linking to /docs/plugins/rethrow-handler.
Documentation & examples
apps/content/docs/plugins/rethrow-handler.md, apps/content/docs/openapi/integrations/implement-contract-in-nest.md
Added new plugin docs page; updated Nest integration examples to import ORPCError and experimental_RethrowHandlerPlugin as RethrowHandlerPlugin and to configure the plugin with a filter that rethrows non-ORPCError errors.
Plugin implementation & public exports
packages/server/src/plugins/rethrow.ts, packages/server/src/plugins/index.ts
Added experimental_RethrowHandlerPlugin (filter-based rethrowing, per-request context via symbol, interceptor wiring) and re-exported it from the plugins barrel.
Tests
packages/server/src/plugins/rethrow.test.ts
Added tests covering rethrow when filter true, suppression when false, ORPCError vs non-ORPCError behavior, filter argument passing, normal flow, and context-corruption handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Focus areas: packages/server/src/plugins/rethrow.ts (interceptor ordering, context symbol lifecycle, filter invocation and return handling), rethrow.test.ts (coverage and edge cases), and the Nest example changes for correct imports/usage.

Possibly related PRs

  • unnoq/orpc#1256 — Related change to Nest integration and plugin usage that this PR builds upon (plugin integration in ORPCModule examples).

Poem

🐰 I nibble bugs and guard the flow,
A filter picks which errors go,
Some bounce back to framework land,
While others rest within my hand,
Hooray — the docs and tests all show! 🎩

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(server): rethrow handler plugin' directly and clearly summarizes the main change: adding a new rethrow handler plugin feature to the server package.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/server/rethrow-plugin

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2bc7a1 and 7437ea4.

📒 Files selected for processing (1)
  • packages/server/src/plugins/rethrow.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: publish-commit
  • GitHub Check: lint
  • GitHub Check: test
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (3)
packages/server/src/plugins/rethrow.ts (3)

1-4: LGTM!

Imports are clean and all are properly used in the implementation.


6-21: LGTM!

The interface is well-documented with a clear example. The filter signature correctly accepts the error and interceptor options for flexible filtering logic.


45-87: LGTM!

The interceptor coordination logic is well-structured:

  • Pre-interceptor correctly uses unshift to catch errors early
  • Context validation provides clear error messaging
  • Filter evaluation and error capture flow is sound
  • Root interceptor properly rethrows captured errors

The comment at line 75 helpfully clarifies the importance of await for catching both sync and async errors.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new RethrowHandlerPlugin for the server. This experimental plugin allows specific errors to be re-thrown from the oRPC handler, enabling integration with framework-level error handling mechanisms like those in NestJS or Express. The implementation is robust, using a combination of root and procedure-level interceptors to achieve the desired behavior. The feature is well-tested, with comprehensive unit tests covering various scenarios, including filtering logic and context corruption. New documentation for the plugin has been added, along with updates to the NestJS integration guide to demonstrate its usage. The changes are of high quality and I have no concerns.

@codecov
Copy link

codecov bot commented Dec 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 10, 2025

More templates

@orpc/ai-sdk

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

@orpc/arktype

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

@orpc/client

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

@orpc/contract

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

@orpc/experimental-durable-iterator

npm i https://pkg.pr.new/@orpc/experimental-durable-iterator@1286

@orpc/hey-api

npm i https://pkg.pr.new/@orpc/hey-api@1286

@orpc/interop

npm i https://pkg.pr.new/@orpc/interop@1286

@orpc/json-schema

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

@orpc/nest

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

@orpc/openapi

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

@orpc/openapi-client

npm i https://pkg.pr.new/@orpc/openapi-client@1286

@orpc/otel

npm i https://pkg.pr.new/@orpc/otel@1286

@orpc/experimental-pino

npm i https://pkg.pr.new/@orpc/experimental-pino@1286

@orpc/experimental-publisher

npm i https://pkg.pr.new/@orpc/experimental-publisher@1286

@orpc/experimental-publisher-durable-object

npm i https://pkg.pr.new/@orpc/experimental-publisher-durable-object@1286

@orpc/experimental-ratelimit

npm i https://pkg.pr.new/@orpc/experimental-ratelimit@1286

@orpc/react

npm i https://pkg.pr.new/@orpc/react@1286

@orpc/react-query

npm i https://pkg.pr.new/@orpc/react-query@1286

@orpc/experimental-react-swr

npm i https://pkg.pr.new/@orpc/experimental-react-swr@1286

@orpc/server

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

@orpc/shared

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

@orpc/solid-query

npm i https://pkg.pr.new/@orpc/solid-query@1286

@orpc/standard-server

npm i https://pkg.pr.new/@orpc/standard-server@1286

@orpc/standard-server-aws-lambda

npm i https://pkg.pr.new/@orpc/standard-server-aws-lambda@1286

@orpc/standard-server-fastify

npm i https://pkg.pr.new/@orpc/standard-server-fastify@1286

@orpc/standard-server-fetch

npm i https://pkg.pr.new/@orpc/standard-server-fetch@1286

@orpc/standard-server-node

npm i https://pkg.pr.new/@orpc/standard-server-node@1286

@orpc/standard-server-peer

npm i https://pkg.pr.new/@orpc/standard-server-peer@1286

@orpc/svelte-query

npm i https://pkg.pr.new/@orpc/svelte-query@1286

@orpc/tanstack-query

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

@orpc/trpc

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

@orpc/valibot

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

@orpc/vue-colada

npm i https://pkg.pr.new/@orpc/vue-colada@1286

@orpc/vue-query

npm i https://pkg.pr.new/@orpc/vue-query@1286

@orpc/zod

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

commit: 7437ea4

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/server/src/plugins/rethrow.ts (1)

36-43: Consider making CONTEXT_SYMBOL readonly.

The symbol is used for internal plugin state coordination. Making it readonly would prevent accidental reassignment.

-  CONTEXT_SYMBOL = Symbol('ORPC_RETHROW_HANDLER_PLUGIN_CONTEXT')
+  readonly CONTEXT_SYMBOL = Symbol('ORPC_RETHROW_HANDLER_PLUGIN_CONTEXT')
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 059b949 and b2bc7a1.

📒 Files selected for processing (6)
  • apps/content/.vitepress/config.ts (1 hunks)
  • apps/content/docs/openapi/integrations/implement-contract-in-nest.md (2 hunks)
  • apps/content/docs/plugins/rethrow-handler.md (1 hunks)
  • packages/server/src/plugins/index.ts (1 hunks)
  • packages/server/src/plugins/rethrow.test.ts (1 hunks)
  • packages/server/src/plugins/rethrow.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/server/src/plugins/rethrow.test.ts (1)
packages/server/src/builder.ts (2)
  • handler (273-280)
  • os (336-352)
packages/server/src/plugins/rethrow.ts (4)
packages/server/src/context.ts (1)
  • Context (1-1)
packages/shared/src/value.ts (1)
  • Value (1-1)
packages/server/src/adapters/standard/handler.ts (2)
  • StandardHandlerInterceptorOptions (23-25)
  • StandardHandlerOptions (27-48)
packages/server/src/adapters/standard/plugin.ts (1)
  • StandardHandlerPlugin (5-8)
🪛 LanguageTool
apps/content/docs/plugins/rethrow-handler.md

[grammar] ~8-~8: Use a hyphen to join words.
Context: ...ul when your framework has its own error handling mechanism (e.g., global excepti...

(QB_NEW_EN_HYPHEN)


[grammar] ~8-~8: Use a hyphen to join words.
Context: ...stead of being handled by the oRPC error handling flow. ## Usage ```ts twoslash...

(QB_NEW_EN_HYPHEN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Agent
  • GitHub Check: lint
  • GitHub Check: test
  • GitHub Check: publish-commit
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (15)
packages/server/src/plugins/index.ts (1)

5-5: LGTM!

The new rethrow export is correctly placed in alphabetical order within the barrel file.

apps/content/.vitepress/config.ts (1)

153-153: LGTM!

Navigation entry correctly added to the Plugins section with proper link path.

apps/content/docs/plugins/rethrow-handler.md (1)

1-38: LGTM!

Clear documentation with a practical usage example. The explanation effectively conveys when and why to use this plugin, particularly for framework integration scenarios like NestJS exception filters.

packages/server/src/plugins/rethrow.test.ts (6)

1-9: LGTM!

Good test setup with vi.clearAllMocks() in beforeEach to ensure clean state between tests.


10-66: LGTM!

Good coverage of the core rethrow behavior - testing both positive (filter returns true → error rethrown) and negative (filter returns false → error handled by oRPC with 500 response) cases. The custom error class test is a nice touch for verifying error identity preservation.


68-102: LGTM!

Excellent test case demonstrating the primary use case: distinguishing between ORPCError (handled by oRPC) and other errors (rethrown to framework). This validates the documented pattern.


104-135: LGTM!

Important test verifying that the filter function receives both the error and the interceptor options (including request and context). This ensures users can make context-aware filtering decisions.


137-159: LGTM!

Good sanity check ensuring the plugin doesn't interfere with normal (non-error) request handling.


161-195: LGTM!

Critical edge case test - verifying graceful degradation when another plugin corrupts the context by removing the plugin's symbol. The 500 response indicates the TypeError is being handled by oRPC's error flow.

apps/content/docs/openapi/integrations/implement-contract-in-nest.md (2)

225-230: LGTM!

Correct imports added for the new plugin integration.


252-260: LGTM!

The RethrowHandlerPlugin configuration demonstrates a practical NestJS integration pattern, allowing non-oRPC errors to bubble up to NestJS global exception filters for centralized error handling.

packages/server/src/plugins/rethrow.ts (4)

1-5: LGTM!

Clean imports with appropriate type-only imports where applicable.


6-25: LGTM!

Well-documented options interface with a clear example in JSDoc. The Value type provides flexibility for both static boolean values and dynamic filter functions. The internal RethrowHandlerPluginContext correctly wraps the error in an object to handle falsy error values.


45-65: LGTM!

The root interceptor correctly:

  1. Creates a fresh plugin context per request
  2. Injects it into the request context via the unique symbol
  3. Rethrows the captured error after the pipeline completes (allowing the error to bubble up to the host framework)

The use of push() ensures this interceptor wraps all other root interceptors, giving it the final say on error handling.


67-87: LGTM!

The interceptor correctly:

  1. Validates the plugin context exists (defensive against context corruption)
  2. Uses unshift() to run before other interceptors, catching errors from the entire chain
  3. Applies the filter to determine rethrow behavior
  4. Returns { matched: false, response: undefined } when capturing an error, allowing the pipeline to complete so the root interceptor can perform the actual rethrow

The await on line 76 is correctly noted as important for catching both sync and async errors.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new experimental RethrowHandlerPlugin that enables selective error rethrowing during request handling, allowing frameworks with built-in error handling mechanisms (e.g., NestJS global exception filters, Express error middleware) to process specific errors instead of oRPC's default error handling flow.

  • Implements a plugin that intercepts errors and decides whether to rethrow them based on a filter function
  • Adds comprehensive test coverage with multiple scenarios including filter function behavior and context corruption handling
  • Includes documentation and integration example for NestJS

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/server/src/plugins/rethrow.ts Main plugin implementation with interceptor logic for catching and selectively rethrowing errors
packages/server/src/plugins/rethrow.test.ts Comprehensive test suite covering filter behavior, context management, and error handling scenarios
packages/server/src/plugins/index.ts Exports the new rethrow plugin
apps/content/docs/plugins/rethrow-handler.md Documentation page explaining the plugin's purpose and usage
apps/content/docs/openapi/integrations/implement-contract-in-nest.md Adds integration example showing how to use the plugin in NestJS applications
apps/content/.vitepress/config.ts Adds navigation entry for the new plugin documentation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 10, 2025

Deploying orpc with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7437ea4
Status: ✅  Deploy successful!
Preview URL: https://e08ec89c.orpc-1qh.pages.dev
Branch Preview URL: https://feat-server-rethrow-plugin.orpc-1qh.pages.dev

View logs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@unnoq unnoq merged commit b2d00a3 into main Dec 18, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants