Skip to content

Feature/graphql error handling#88

Merged
joadan merged 1 commit intoLinq2GraphQL:mainfrom
ricred:feature/graphql-error-handling
Apr 21, 2026
Merged

Feature/graphql error handling#88
joadan merged 1 commit intoLinq2GraphQL:mainfrom
ricred:feature/graphql-error-handling

Conversation

@ricred
Copy link
Copy Markdown
Contributor

@ricred ricred commented Apr 20, 2026

Problem
The generated client silently swallowed GraphQL errors. ExecuteAsync threw a bare exception with no structured error data — no extensions, no error codes, no locations, no paths. Subscription errors were completely lost. There was no way to access both data and errors from a partial response.
Solution
Full GraphQL error propagation following the GraphQL spec §7.1 Response Format (https://spec.graphql.org/October2021/#sec-Response):

  • GraphQueryError now carries Message, Locations, Path, Extensions, and a classified ErrorCode
  • GraphResult exposes Data, Errors, Extensions, HasErrors, HasData, EnsureNoErrors()
  • ExecuteWithResultAsync() — opt-in Result API (no throw, get data + errors)
  • ExecuteAsync() — existing API unchanged, now throws with full error details
  • Subscription error handling for both WS (graphql-ws) and SSE protocols

What's New

  • Add GraphQueryError with Extensions, ErrorCode, Locations, Path
  • Add GraphErrorCode enum (Apollo + Hot Chocolate codes)
  • Add GraphResult with Data, Errors, Extensions, HasErrors, HasData
  • Add ExecuteWithResultAsync() for queries, mutations, cursor paging
  • Add ProcessResponseFull() parsing full GraphQL response (data + errors + extensions)
  • Handle WS error/complete messages, SSE event: error
  • Add SafeProcessMessage for subscription resilience
  • Add 32 error handling tests (99 total pass)
  • Add Error Handling docs to README

API
Existing — backward compatible, now with rich error details:

try
{
    var result = await client.Query.Customer(id: "abc").Select().ExecuteAsync();
}
catch (GraphQueryExecutionException ex)
{
    var code = ex.Errors.First().ErrorCode;   // GraphErrorCode.Authentication
    var ext  = ex.Errors.First().Extensions;   // full server extensions
}

New — Result API, no exceptions:

var result = await client.Query.Customer(id: "abc").Select().ExecuteWithResultAsync();
if (result.HasErrors) { /* inspect result.Errors */ }
if (result.HasData)   { /* use result.Data */ }

Changes
Core — QueryExecutor.cs, GraphQueryExecute.cs, GraphBaseExecute.cs, GraphCursorPager.cs
→ ProcessResponseFull, ExecuteRawAsync, ExecuteWithResultAsync, paging variants
Types — GraphErrorCode.cs (new), GraphResult.cs (new), GraphQueryExecutionException.cs
→ Error classification (Apollo + Hot Chocolate codes), result wrapper, extensions on error
Subscriptions — WSClient.cs, SSEClient.cs, GraphSubscriptionExecute.cs, WebsocketRequestTypes.cs
→ WS error/complete messages, SSE event: error, SafeProcessMessage resilience
Tests — ErrorHandlingTests.cs (new), Query.cs (test server)
→ 32 new tests (99 total pass), error-raising test endpoints
Docs — README.md
→ Error Handling section with examples

Backward Compatibility
Fully backward compatible. ExecuteAsync() signature unchanged. New APIs are additive opt-in.

…ption resilience

- Add GraphQueryError with Extensions, ErrorCode, Locations, Path
- Add GraphErrorCode enum (Apollo + Hot Chocolate codes)
- Add GraphResult<T> with Data, Errors, Extensions, HasErrors, HasData
- Add ExecuteWithResultAsync() for queries, mutations, cursor paging
- Add ProcessResponseFull() parsing full GraphQL response (data+errors+extensions)
- Handle WS error/complete messages, SSE event:error
- Add SafeProcessMessage for subscription resilience
- Add 32 error handling tests (99 total pass)
- Add Error Handling docs to README
@joadan joadan merged commit c06fb05 into Linq2GraphQL:main Apr 21, 2026
1 check 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