Skip to content

refactor!: move error handler to schema#611

Merged
stuebingerb merged 1 commit into
mainfrom
refactor/move-error-handler-to-schema
May 13, 2026
Merged

refactor!: move error handler to schema#611
stuebingerb merged 1 commit into
mainfrom
refactor/move-error-handler-to-schema

Conversation

@stuebingerb
Copy link
Copy Markdown
Owner

Moves the error handler from the Ktor plugin to the schema itself. The error handler can now be used to map any exception encountered during execution and delegate to the default implementation.

BREAKING CHANGE: error handler is no longer supported as part of Ktor plugin configuration

@stuebingerb stuebingerb force-pushed the refactor/move-error-handler-to-schema branch from 3099697 to 969f4cb Compare April 15, 2026 15:55
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 15, 2026

Codecov Report

❌ Patch coverage is 86.95652% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.13%. Comparing base (5f911e1) to head (e3c9ee1).

Files with missing lines Patch % Lines
.../main/kotlin/com/apurebase/kgraphql/KtorFeature.kt 0.00% 1 Missing ⚠️
...purebase/kgraphql/schema/execution/ErrorHandler.kt 85.71% 0 Missing and 1 partial ⚠️
...raphql/schema/execution/ParallelRequestExecutor.kt 85.71% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #611      +/-   ##
==========================================
+ Coverage   84.10%   84.13%   +0.03%     
==========================================
  Files         151      152       +1     
  Lines        5000     5006       +6     
  Branches      860      861       +1     
==========================================
+ Hits         4205     4212       +7     
  Misses        495      495              
+ Partials      300      299       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 15, 2026

🐰 Bencher Report

Branchrefactor/move-error-handler-to-schema
Testbedubuntu-latest

🚨 1 Alert

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Lower Boundary
(Limit %)
com.apurebase.kgraphql.RequestCachingBenchmark.invalidRequestThroughput
operations / second (ops/s) x 1e3
📈 plot
🚷 threshold
🚨 alert (🔔)
140.30 ops/s x 1e3
(-37.58%)Baseline: 224.78 ops/s x 1e3
186.08 ops/s x 1e3
(132.64%)

Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
com.apurebase.kgraphql.FunctionExecutionBenchmark.benchmarkFunctionExecution📈 view plot
🚷 view threshold
5,878,610.38 ops/s
(+0.95%)Baseline: 5,823,131.05 ops/s
4,983,513.57 ops/s
(84.77%)
com.apurebase.kgraphql.ParallelExecutionBenchmark.queryBenchmark📈 view plot
🚷 view threshold
1.30 ops/s
(+0.07%)Baseline: 1.30 ops/s
1.29 ops/s
(99.72%)
com.apurebase.kgraphql.QueryBenchmark.executionError📈 view plot
🚷 view threshold
17,953.25 ops/s
(+3.71%)Baseline: 17,310.26 ops/s
10,616.82 ops/s
(59.14%)
com.apurebase.kgraphql.QueryBenchmark.inputFromDocument📈 view plot
🚷 view threshold
21,635.19 ops/s
(-2.03%)Baseline: 22,083.83 ops/s
15,145.64 ops/s
(70.00%)
com.apurebase.kgraphql.QueryBenchmark.inputFromVariable📈 view plot
🚷 view threshold
20,939.39 ops/s
(-0.82%)Baseline: 21,112.57 ops/s
14,396.51 ops/s
(68.75%)
com.apurebase.kgraphql.QueryBenchmark.largeList📈 view plot
🚷 view threshold
4.67 ops/s
(+4.69%)Baseline: 4.46 ops/s
3.71 ops/s
(79.28%)
com.apurebase.kgraphql.QueryBenchmark.largeListWithFragment📈 view plot
🚷 view threshold
5.13 ops/s
(+3.55%)Baseline: 4.95 ops/s
4.17 ops/s
(81.26%)
com.apurebase.kgraphql.QueryBenchmark.manyChildren📈 view plot
🚷 view threshold
189.23 ops/s
(+1.70%)Baseline: 186.07 ops/s
142.29 ops/s
(75.19%)
com.apurebase.kgraphql.QueryBenchmark.manyChildrenWithFragment📈 view plot
🚷 view threshold
200.21 ops/s
(-5.28%)Baseline: 211.38 ops/s
160.97 ops/s
(80.40%)
com.apurebase.kgraphql.QueryBenchmark.manyDataChildren📈 view plot
🚷 view threshold
8.91 ops/s
(-0.23%)Baseline: 8.93 ops/s
8.80 ops/s
(98.73%)
com.apurebase.kgraphql.QueryBenchmark.manyOperations📈 view plot
🚷 view threshold
308.84 ops/s
(+12.16%)Baseline: 275.35 ops/s
200.55 ops/s
(64.94%)
com.apurebase.kgraphql.QueryBenchmark.manyOperationsWithFragment📈 view plot
🚷 view threshold
318.94 ops/s
(+11.08%)Baseline: 287.14 ops/s
214.76 ops/s
(67.33%)
com.apurebase.kgraphql.QueryBenchmark.nestedObject📈 view plot
🚷 view threshold
8,144.99 ops/s
(+9.30%)Baseline: 7,451.97 ops/s
5,610.68 ops/s
(68.89%)
com.apurebase.kgraphql.RequestCachingBenchmark.invalidRequest📈 view plot
🚷 view threshold
🚨 view alert (🔔)
140,295.49 ops/s
(-37.58%)Baseline: 224,777.64 ops/s
186,083.25 ops/s
(132.64%)

com.apurebase.kgraphql.RequestCachingBenchmark.largeRequest📈 view plot
🚷 view threshold
8,000.36 ops/s
(+3.15%)Baseline: 7,756.30 ops/s
5,952.75 ops/s
(74.41%)
com.apurebase.kgraphql.RequestCachingBenchmark.smallRequest📈 view plot
🚷 view threshold
11,844.17 ops/s
(+4.29%)Baseline: 11,357.44 ops/s
8,343.65 ops/s
(70.45%)
com.apurebase.kgraphql.SimpleExecutionOverheadBenchmark.benchmark📈 view plot
🚷 view threshold
475,647.22 ops/s
(+0.33%)Baseline: 474,069.55 ops/s
419,449.77 ops/s
(88.19%)
🐰 View full continuous benchmarking report in Bencher

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 16 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docs/content/Reference/configuration.md">

<violation number="1" location="docs/content/Reference/configuration.md:14">
P3: The `errorHandler` documentation link points to a non-existent source path (`com/stuebingerb`) and should use the actual `com/apurebase` path.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread docs/content/Reference/configuration.md Outdated
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added schema-level custom error handler configuration for mapping exceptions during GraphQL execution
  • Documentation

    • Updated error handling documentation with custom handler examples and behavior specifications
    • Updated configuration reference with new error handler property
    • Refined Ktor plugin documentation for clarity

Walkthrough

This PR refactors exception handling in KGraphQL by introducing a schema-level, pluggable ErrorHandler class that centralizes exception-to-GraphQLError mapping during query execution. The plugin-level error handler configuration is removed from Ktor, and documentation is updated to reflect the new schema-based model.

Changes

Error Handler Integration and Ktor Plugin Refactoring

Layer / File(s) Summary
Core ErrorHandler class and schema integration
kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ErrorHandler.kt, kgraphql/src/main/kotlin/com/apurebase/kgraphql/configuration/SchemaConfiguration.kt, kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/dsl/SchemaConfigurationDSL.kt, kgraphql/api/kgraphql.api
New open ErrorHandler class provides default exception-to-GraphQLError mapping. SchemaConfiguration and SchemaConfigurationDSL accept and expose an errorHandler property; non-GraphQL exceptions are wrapped in ExecutionError with the original throwable preserved as cause.
Execution layer error handling
kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt, kgraphql/src/test/kotlin/com/apurebase/kgraphql/integration/QueryTest.kt
handleException becomes suspend and delegates all non-cancellation errors to schema.configuration.errorHandler. Routes RequestError directly and conditionally handles ExecutionError based on field nullability. Integration test validates custom handlers mapping IllegalArgumentException to ExecutionError and IllegalAccessException to RequestError with custom extensions.
Stitched schema error handler propagation
kgraphql-ktor-stitched/src/main/kotlin/com/apurebase/kgraphql/stitched/schema/configuration/StitchedSchemaConfiguration.kt, kgraphql-ktor-stitched/src/main/kotlin/com/apurebase/kgraphql/stitched/schema/dsl/StitchedSchemaConfigurationDSL.kt, kgraphql-ktor-stitched/api/kgraphql-ktor-stitched.api
StitchedSchemaConfiguration constructor now accepts errorHandler and forwards it to SchemaConfiguration superclass; DSL's build() method passes the configured handler through.
Ktor plugin error handler removal
kgraphql-ktor/src/main/kotlin/com/apurebase/kgraphql/KtorFeature.kt, kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorFeatureTest.kt, kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorTest.kt, kgraphql-ktor/api/kgraphql-ktor.api
Plugin-level errorHandler configuration function and internal storage are removed from GraphQL.Configuration. Pipeline's monitoring interceptor now catches only GraphQLError and serializes directly via e.serialize(), eliminating custom exception mapping at the Ktor layer.
Documentation updates
docs/content/Plugins/ktor.md, docs/content/Reference/configuration.md, docs/content/Reference/errorHandling.md
Ktor plugin docs remove errorHandler configuration table row and "Error Handler" section. Configuration reference adds errorHandler property with ErrorHandler default. Error handling guide expands wrapErrors = false behavior documentation and adds new "Error Handler" section explaining schema-configured error handling, custom mapping patterns with example override, and guarantee that errors from the handler itself are never wrapped.

Sequence Diagram

sequenceDiagram
  participant User as User Code
  participant Schema as SchemaConfiguration
  participant Executor as ParallelRequestExecutor
  participant Handler as ErrorHandler
  participant Resp as Response
  User->>Schema: configure(errorHandler = CustomHandler)
  Schema->>Schema: store errorHandler instance
  User->>Executor: execute query
  Executor->>Executor: field resolution error occurs
  Executor->>Handler: handleException(ctx, node, exception)
  alt Custom mapping matches
    Handler->>Handler: map to ExecutionError or RequestError
  else No match
    Handler->>Handler: call super (default mapping)
  end
  Handler-->>Executor: GraphQLError subclass
  alt RequestError
    Executor->>Resp: rethrow (halts request)
  else ExecutionError + nullable field
    Executor->>Resp: raise error, return null for field
  else ExecutionError + non-nullable field
    Executor->>Resp: propagate error upward
  end
Loading

Possibly related PRs

  • stuebingerb/KGraphQL#610: Refactors RequestError/ExecutionError distinction and centralizes handleException behavior, directly enabling the pluggable ErrorHandler pattern introduced in this PR.

Suggested reviewers

  • mervyn-mccreight
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: moving error handler responsibility from the Ktor plugin to the schema layer, using conventional commits format with breaking change indicator.
Description check ✅ Passed The description directly relates to the changeset, explaining the migration of error handler from Ktor plugin to schema and noting the breaking change, which aligns with all documented modifications.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/move-error-handler-to-schema

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
Copy Markdown

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/content/Reference/configuration.md`:
- Around line 12-14: Update the docs to show the correct default and link: add
the default value `true` for the wrapErrors entry to reflect
SchemaConfigurationDSL.wrapErrors being initialized to true, and fix the
ErrorHandler reference URL to point to the current package path (replace
com/stuebingerb/.../ErrorHandler.kt with com/apurebase/.../ErrorHandler.kt) so
the link resolves to the actual ErrorHandler source.

In
`@kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt`:
- Around line 477-482: Call the schema errorHandler before deciding to rethrow
so custom handlers can remap exceptions even when
schema.configuration.wrapErrors is false: do not early-return when
!schema.configuration.wrapErrors; instead, first check for CancellationException
and skip handling for that case, otherwise invoke
schema.configuration.errorHandler.handleException(ctx.requestContext, node,
exception), then if that returns a RequestError throw it; finally, if wrapErrors
is false rethrow the original exception, else continue with the existing
wrapping logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f80ca7ab-d1e9-4a12-a707-a482238631b2

📥 Commits

Reviewing files that changed from the base of the PR and between c70d308 and 969f4cb.

📒 Files selected for processing (16)
  • docs/content/Plugins/ktor.md
  • docs/content/Reference/configuration.md
  • docs/content/Reference/errorHandling.md
  • kgraphql-ktor-stitched/api/kgraphql-ktor-stitched.api
  • kgraphql-ktor-stitched/src/main/kotlin/com/apurebase/kgraphql/stitched/schema/configuration/StitchedSchemaConfiguration.kt
  • kgraphql-ktor-stitched/src/main/kotlin/com/apurebase/kgraphql/stitched/schema/dsl/StitchedSchemaConfigurationDSL.kt
  • kgraphql-ktor/api/kgraphql-ktor.api
  • kgraphql-ktor/src/main/kotlin/com/apurebase/kgraphql/KtorFeature.kt
  • kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorFeatureTest.kt
  • kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorTest.kt
  • kgraphql/api/kgraphql.api
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/configuration/SchemaConfiguration.kt
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/dsl/SchemaConfigurationDSL.kt
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ErrorHandler.kt
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt
  • kgraphql/src/test/kotlin/com/apurebase/kgraphql/integration/QueryTest.kt
💤 Files with no reviewable changes (3)
  • kgraphql-ktor/api/kgraphql-ktor.api
  • kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorFeatureTest.kt
  • kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorTest.kt

Comment thread docs/content/Reference/configuration.md Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 16 files

Architecture diagram
sequenceDiagram
    participant Client as Client (HTTP)
    participant Ktor as Ktor Plugin
    participant Exec as ParallelRequestExecutor
    participant Handler as NEW: ErrorHandler (Schema)
    participant Resolver as Resolver (User Code)

    Note over Client,Resolver: GraphQL Execution Flow with Error Handling

    Client->>Ktor: POST /graphql
    Ktor->>Exec: execute(query)
    
    Exec->>Resolver: Invoke resolver
    
    alt Success Path
        Resolver-->>Exec: Data
        Exec-->>Ktor: Execution Result
        Ktor-->>Client: 200 OK (JSON Data)
    else Resolver throws Exception
        Resolver-->>Exec: throw Throwable
        
        Exec->>Handler: NEW: handleException(ctx, node, exception)
        Note right of Handler: Maps Throwable to GraphQLError
        Handler-->>Exec: Return GraphQLError (e.g. ExecutionError)
        
        alt Field is Nullable
            Exec->>Exec: Add error to result context
            Exec-->>Ktor: Result (Data + Errors)
            Ktor-->>Client: 200 OK (Partial JSON)
        else Field is Non-Nullable
            Exec-->>Ktor: CHANGED: throw GraphQLError
            Ktor->>Ktor: Catch GraphQLError
            Ktor-->>Client: 200 OK (JSON Errors only)
        end
    end

    Note over Ktor,Handler: BREAKING: Error mapping moved from Ktor Plugin to Schema Config
Loading

@stuebingerb stuebingerb force-pushed the feature/support-partial-responses branch 3 times, most recently from f71014d to bdf5538 Compare May 12, 2026 18:17
Base automatically changed from feature/support-partial-responses to main May 12, 2026 18:50
Moves the error handler from the Ktor plugin to the schema itself. The
error handler can now be used to map any exception encountered during
execution and delegate to the default implementation.

BREAKING CHANGE: error handler is no longer supported as part of Ktor
plugin configuration
@stuebingerb stuebingerb force-pushed the refactor/move-error-handler-to-schema branch from 969f4cb to e3c9ee1 Compare May 12, 2026 18:58
@stuebingerb stuebingerb marked this pull request as ready for review May 12, 2026 18:58
Copy link
Copy Markdown

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

🧹 Nitpick comments (1)
kgraphql/src/test/kotlin/com/apurebase/kgraphql/integration/QueryTest.kt (1)

1211-1235: ⚡ Quick win

Add an assertion for the super.handleException(...) fallback path.

Line 1211 delegates to default handling, but this path is currently untested. Add a third query that throws an unmapped exception and assert default error output.

Proposed test extension
         val schema = KGraphQL.schema {
             configure {
                 errorHandler = customErrorHandler
             }
             query("executionError") {
                 resolver<String?> { throw IllegalArgumentException("Illegal argument") }
             }
             query("requestError") {
                 resolver<String?> { throw IllegalAccessException() }
             }
+            query("defaultError") {
+                resolver<String?> { throw RuntimeException("Boom") }
+            }
         }
@@
         schema.executeBlocking("{ requestError }") shouldBe """
             {"errors":[{"message":"You shall not pass!","locations":[{"line":1,"column":3}],"extensions":{"required_role":"ADMIN","reason":"Gandalf"}}]}
         """.trimIndent()
+
+        schema.executeBlocking("{ defaultError }") shouldBe """
+            {"errors":[{"message":"Boom","locations":[{"line":1,"column":3}],"path":["defaultError"],"extensions":{"type":"INTERNAL_SERVER_ERROR"}}],"data":{"defaultError":null}}
+        """.trimIndent()
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kgraphql/src/test/kotlin/com/apurebase/kgraphql/integration/QueryTest.kt`
around lines 1211 - 1235, Add a test for the fallback path of customErrorHandler
by adding a third query in the same schema (e.g., query "unmappedError" with a
resolver that throws an unmapped exception like IllegalStateException) and
assert that schema.executeBlocking("{ unmappedError }") returns the default
error shape produced by super.handleException (including standard "message",
"locations" and "path" fields and no custom "extensions"). Locate the
customErrorHandler and its handleException override in the test and extend the
schema block and assertions accordingly so the fallback path is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@kgraphql/src/test/kotlin/com/apurebase/kgraphql/integration/QueryTest.kt`:
- Around line 1211-1235: Add a test for the fallback path of customErrorHandler
by adding a third query in the same schema (e.g., query "unmappedError" with a
resolver that throws an unmapped exception like IllegalStateException) and
assert that schema.executeBlocking("{ unmappedError }") returns the default
error shape produced by super.handleException (including standard "message",
"locations" and "path" fields and no custom "extensions"). Locate the
customErrorHandler and its handleException override in the test and extend the
schema block and assertions accordingly so the fallback path is covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 65545a8a-a026-4cec-bb57-c24cd4fd8852

📥 Commits

Reviewing files that changed from the base of the PR and between 969f4cb and e3c9ee1.

📒 Files selected for processing (16)
  • docs/content/Plugins/ktor.md
  • docs/content/Reference/configuration.md
  • docs/content/Reference/errorHandling.md
  • kgraphql-ktor-stitched/api/kgraphql-ktor-stitched.api
  • kgraphql-ktor-stitched/src/main/kotlin/com/apurebase/kgraphql/stitched/schema/configuration/StitchedSchemaConfiguration.kt
  • kgraphql-ktor-stitched/src/main/kotlin/com/apurebase/kgraphql/stitched/schema/dsl/StitchedSchemaConfigurationDSL.kt
  • kgraphql-ktor/api/kgraphql-ktor.api
  • kgraphql-ktor/src/main/kotlin/com/apurebase/kgraphql/KtorFeature.kt
  • kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorFeatureTest.kt
  • kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorTest.kt
  • kgraphql/api/kgraphql.api
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/configuration/SchemaConfiguration.kt
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/dsl/SchemaConfigurationDSL.kt
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ErrorHandler.kt
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt
  • kgraphql/src/test/kotlin/com/apurebase/kgraphql/integration/QueryTest.kt
💤 Files with no reviewable changes (3)
  • kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorTest.kt
  • kgraphql-ktor/api/kgraphql-ktor.api
  • kgraphql-ktor/src/test/kotlin/com/apurebase/kgraphql/KtorFeatureTest.kt
✅ Files skipped from review due to trivial changes (1)
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ErrorHandler.kt
🚧 Files skipped from review as they are similar to previous changes (7)
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/dsl/SchemaConfigurationDSL.kt
  • kgraphql-ktor-stitched/src/main/kotlin/com/apurebase/kgraphql/stitched/schema/dsl/StitchedSchemaConfigurationDSL.kt
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/configuration/SchemaConfiguration.kt
  • kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt
  • docs/content/Reference/errorHandling.md
  • kgraphql/api/kgraphql.api
  • kgraphql-ktor/src/main/kotlin/com/apurebase/kgraphql/KtorFeature.kt

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 16 files

Architecture diagram
sequenceDiagram
    participant Client
    participant Ktor as Ktor Plugin
    participant Schema as Schema
    participant Config as Schema Configuration
    participant Executor as ParallelRequestExecutor
    participant ErrorHandler as ErrorHandler
    participant Resolver as Resolver

    Note over Client,Resolver: NEW: Error handling moved from Ktor plugin to Schema

    Client->>Ktor: POST /graphql
    Ktor->>Schema: executeQuery(query, context)
    
    Schema->>Executor: execute(request)
    
    Executor->>Resolver: resolveField()
    alt Exception thrown by resolver
        Resolver-->>Executor: Throwable
        Executor->>Executor: handleException(ctx, node, type, throwable)
        
        alt wrapErrors = false OR CancellationException
            Executor->>Executor: throw exception (no handling)
        else NEW: Call error handler on Schema
            Executor->>ErrorHandler: handleException(ctx, node, exception)
            alt Result is RequestError
                ErrorHandler-->>Executor: RequestError
                Executor->>Executor: throw RequestError
            else Result is ExecutionError AND field nullable
                ErrorHandler-->>Executor: ExecutionError
                Executor->>Executor: raiseError + return null node
            else Result is ExecutionError AND field non-nullable
                ErrorHandler-->>Executor: ExecutionError
                Executor->>Executor: throw ExecutionError
            end
        end
    end
    
    alt Exception propagated to Ktor
        Ktor->>Ktor: catch GraphQLError
        Ktor->>Client: 200 + serialized error
    else Normal execution
        Schema-->>Ktor: result
        Ktor->>Client: 200 + response
    end

    Note over ErrorHandler: Default: GraphQLError -> pass through<br/>Other -> wrap as ExecutionError
    Note over Config: Configurable via schema configuration<br/>errorHandler property
Loading

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 16 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docs/content/Reference/errorHandling.md">

<violation number="1" location="docs/content/Reference/errorHandling.md:227">
P2: The new guidance is internally inconsistent: it tells users to re-throw mapped exceptions, but the documented error-handler API returns mapped `GraphQLError`s. This should instruct returning mapped errors instead of re-throwing exceptions.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Client
    participant Ktor as Ktor Plugin
    participant Schema as Schema
    participant Config as Schema Configuration
    participant Executor as ParallelRequestExecutor
    participant ErrorHandler as ErrorHandler
    participant Resolver as Resolver

    Note over Client,Resolver: NEW: Error handling moved from Ktor plugin to Schema

    Client->>Ktor: POST /graphql
    Ktor->>Schema: executeQuery(query, context)
    
    Schema->>Executor: execute(request)
    
    Executor->>Resolver: resolveField()
    alt Exception thrown by resolver
        Resolver-->>Executor: Throwable
        Executor->>Executor: handleException(ctx, node, type, throwable)
        
        alt wrapErrors = false OR CancellationException
            Executor->>Executor: throw exception (no handling)
        else NEW: Call error handler on Schema
            Executor->>ErrorHandler: handleException(ctx, node, exception)
            alt Result is RequestError
                ErrorHandler-->>Executor: RequestError
                Executor->>Executor: throw RequestError
            else Result is ExecutionError AND field nullable
                ErrorHandler-->>Executor: ExecutionError
                Executor->>Executor: raiseError + return null node
            else Result is ExecutionError AND field non-nullable
                ErrorHandler-->>Executor: ExecutionError
                Executor->>Executor: throw ExecutionError
            end
        end
    end
    
    alt Exception propagated to Ktor
        Ktor->>Ktor: catch GraphQLError
        Ktor->>Client: 200 + serialized error
    else Normal execution
        Schema-->>Ktor: result
        Ktor->>Client: 200 + response
    end

    Note over ErrorHandler: Default: GraphQLError -> pass through<br/>Other -> wrap as ExecutionError
    Note over Config: Configurable via schema configuration<br/>errorHandler property
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Because thrown exceptions are re-thrown, `wrapErrors = false` will not produce partial responses from thrown exceptions,
but resolvers can still return partial responses by calling `Context.raiseError`. `wrapErrors = false` will also not
invoke a custom error handler. If you want to throw exceptions with custom mapping, use `wrapErrors = true` and re-throw
mapped exceptions from the error handler.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The new guidance is internally inconsistent: it tells users to re-throw mapped exceptions, but the documented error-handler API returns mapped GraphQLErrors. This should instruct returning mapped errors instead of re-throwing exceptions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/content/Reference/errorHandling.md, line 227:

<comment>The new guidance is internally inconsistent: it tells users to re-throw mapped exceptions, but the documented error-handler API returns mapped `GraphQLError`s. This should instruct returning mapped errors instead of re-throwing exceptions.</comment>

<file context>
@@ -221,4 +221,42 @@ Those re-thrown exceptions could then be handled with the [`StatusPages` Ktor pl
+Because thrown exceptions are re-thrown, `wrapErrors = false` will not produce partial responses from thrown exceptions,
+but resolvers can still return partial responses by calling `Context.raiseError`. `wrapErrors = false` will also not
+invoke a custom error handler. If you want to throw exceptions with custom mapping, use `wrapErrors = true` and re-throw
+mapped exceptions from the error handler. 
+
+## Error Handler
</file context>

@stuebingerb stuebingerb merged commit e5ac77f into main May 13, 2026
12 of 13 checks passed
@stuebingerb stuebingerb deleted the refactor/move-error-handler-to-schema branch May 13, 2026 08:42
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