Skip to content

web: capture the real GraphQL error message at the network layer - #155

Open
sdunster wants to merge 1 commit into
pr153from
pr154
Open

web: capture the real GraphQL error message at the network layer#155
sdunster wants to merge 1 commit into
pr153from
pr154

Conversation

@sdunster

@sdunster sdunster commented Aug 21, 2026

Copy link
Copy Markdown
Member

Neither the Relay field-logger nor the message-recovery fix (prior
commit) can surface the real message for most server-side field
failures: async-graphql omits a failed field's key from the response
entirely rather than sending it as explicit null, and Relay's
normalizer only attaches an error to a record when it sees an
explicit null — an absent key takes an earlier branch that warns and
returns before ever consulting the error list. So
relay_field_payload.error (the one Relay event that carries a
message) essentially never fires for a real query-side resolver
failure, and the field logger's own console output shows a path with
no explanation.

fetchGraphQL now reads response.errors directly off every parsed
response, for every operation kind, before Relay ever touches it —
sidestepping the normalizer question entirely. Each response with
errors gets an immediate [graphql-error] console log with the full
raw error list (message, path, locations, extensions), and the
messages are buffered via relayFieldLogger's
recordServerErrorMessages, so describeCaughtError can still recover
them later for on-screen display once a generic Relay throw reaches
an error boundary. This fixes the console-logging gap immediately,
independent of whether @throwOnFieldError is applied to the query
that failed.

Query captures never throw, unlike the existing mutation path
(unaffected, still throws MutationFieldError) — some field.error
combinations are legitimate degradation (e.g. an absorber field
resolving to null), and query components already have their own
suspense/render flow to interrupt only when a boundary is meant to
catch something.


Stack created with Sapling. Best reviewed with ReviewStack.

Neither the Relay field-logger nor the message-recovery fix (prior
commit) can surface the real message for most server-side field
failures: async-graphql omits a failed field's key from the response
entirely rather than sending it as explicit null, and Relay's
normalizer only attaches an error to a record when it sees an
explicit null — an absent key takes an earlier branch that warns and
returns before ever consulting the error list. So
relay_field_payload.error (the one Relay event that carries a
message) essentially never fires for a real query-side resolver
failure, and the field logger's own console output shows a path with
no explanation.

fetchGraphQL now reads response.errors directly off every parsed
response, for every operation kind, before Relay ever touches it —
sidestepping the normalizer question entirely. Each response with
errors gets an immediate `[graphql-error]` console log with the full
raw error list (message, path, locations, extensions), and the
messages are buffered via relayFieldLogger's
recordServerErrorMessages, so describeCaughtError can still recover
them later for on-screen display once a generic Relay throw reaches
an error boundary. This fixes the console-logging gap immediately,
independent of whether @throwOnFieldError is applied to the query
that failed.

Query captures never throw, unlike the existing mutation path
(unaffected, still throws MutationFieldError) — some field.error
combinations are legitimate degradation (e.g. an absorber field
resolving to null), and query components already have their own
suspense/render flow to interrupt only when a boundary is meant to
catch something.
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