Skip to content

Implement onError proposal - #4364

Open
benjie wants to merge 47 commits into
16.x.xfrom
on-error
Open

Implement onError proposal#4364
benjie wants to merge 47 commits into
16.x.xfrom
on-error

Conversation

@benjie

@benjie benjie commented Mar 27, 2025

Copy link
Copy Markdown
Member

@github-actions

Copy link
Copy Markdown

Hi @benjie, I'm @github-actions bot happy to help you with this PR 👋

Supported commands

Please post this commands in separate comments and only one per comment:

  • @github-actions run-benchmark - Run benchmark comparing base and merge commits for this PR
  • @github-actions publish-pr-on-npm - Build package from this PR and publish it on NPM

@benjie

This comment has been minimized.

@github-actions

Copy link
Copy Markdown

@github-actions publish-pr-on-npm

@benjie The latest changes of this PR are available on NPM as
graphql@16.10.0-canary.pr.4364.6b142546832c1283b535908fb8c9a171b2f7cc20
Note: no gurantees provided so please use your own discretion.

Also you can depend on latest version built from this PR:
npm install --save graphql@canary-pr-4364

@JoviDeCroock JoviDeCroock 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 am not opposed to this but what are we doing with the directive that is present on main/v17?

Comment thread src/execution/execute.ts
@benjie
benjie marked this pull request as draft April 10, 2025 14:58
@benjie

benjie commented Apr 10, 2025

Copy link
Copy Markdown
Member Author

I want to add an introspection field indicating the default error behavior of a schema, so I've moved this to draft.

@JoviDeCroock

Copy link
Copy Markdown
Contributor

Regarding the introspection, would we have a non-repeatable schema-directive then that indicates what kind of error-propagation we are dealing with? I think that would make sense, the server can internally dictate what the default is and it can be externally requested to be different by means of the request-parameter.

I think we can merge these separately though, the default for all would be PROPAGATE at the moment so there's no need yet for the schema-directive. The name errorPolicy sounds quite good to me for the introspection field.

@benjie

benjie commented Apr 17, 2025

Copy link
Copy Markdown
Member Author

Exactly that, yes. schema @behavior(onError: NO_PROPAGATE) { query: Query } or some such.

We can do them separate, but I'd like to make it so that the presence of the field in introspection also implies the support for the parameter and vice versa.

@martinbonnin

Copy link
Copy Markdown
Contributor

Should this target the v17 branch?

@egoodwinx

Copy link
Copy Markdown

hey benjie - wondering the status on this and when it will be available in 17? I want to look at implementing this in some js libraries.

@benjie benjie left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This implements the latest version of graphql/graphql-spec#1163:

  • Removed all the introspection code
  • Removed "default error behavior" as discussed at last Spec WG
  • Introduced pathNonNull as discussed at last Spec WG
  • Merged the latest 16.x.x branch
  • Added comments and extended tests to pass linting

I'm working on a new project that'll show how this new error/nullability system can shine across all clients with minimal code; but I don't think it'll be ready until late September. In the mean time, it would be helpful to have an experimental release of this out for people to experiment with.

Note: I've used the @experimental TSDoc tag to mark methods/interfaces/etc as experimental, this should make it easier for people to adopt whilst still being aware they're using something that may change in a patch release. https://tsdoc.org/pages/tags/experimental/

Comment thread src/error/locatedError.ts

function isLocatedGraphQLError(error: any): error is GraphQLError {
return Array.isArray(error.path);
return Array.isArray(error.path) && Array.isArray(error.pathNonNull);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is the main potentially breaking change in this PR. Options:

  1. (This option) If an error does not contain pathNonNull then it's (no longer) a located error, and should be wrapped with a GraphQL error that is.
  2. Allow poorly located errors - those without pathNoNull, through when they originate in user code.

IMO user code should not be raising errors with path anyway (and doing so potentially enables them to break GraphQL spec compliance), so I personally feel this is a moot point and am happy adding this change.

Comment thread src/execution/execute.ts Outdated
Comment thread src/execution/execute.ts Outdated
Comment thread src/jsutils/Path.ts
curr = curr.prev;
}
return flattened.reverse();
return [...pathToDigest(path).path];

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Annoyingly we said this was mutable before, so we need to clone the array. (This allows us to make pathToDigest memoized in future.)

@benjie
benjie marked this pull request as ready for review August 13, 2026 13:44
benjie added 8 commits August 13, 2026 14:45
This is one of those rare cases where you _do_ want the `{}` type. `{}`
means essentially "any non-null value" - it could be an object, array,
number, symbol, anything. So `{} | null` is essentially
`Exclude<any, undefined>` (which you can't actually do). That's actually
what we want here: `{} | null` is just one step up from `unknown`: we
don't know anything about it _except_ that it's not `undefined`. And
for us `undefined` was significant, so excluding it reduces the number
of branches we need.
@benjie

benjie commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

Good timing @egoodwinx! I've just spent the day bringing this up to date. If we get this merged into v16 we can forward-port it to v17 or vice-versa. I've not attempted to reconcile it with incremental delivery yet, but I've tried to be careful in the wording to allow for it (e.g. for the ABORT mode it is essentially described as bubbling to the highest position it can, typically the operation root; but in incremental delivery it will be the individual incremental units).

@benjie

benjie commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

GraphQL v17 port, mostly performed by codex: #4846

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.

5 participants