Skip to content

Commit 584550a

Browse files
docs: understanding graphql errors (#4382)
Adds a guide "Understanding GraphQL.js Errors" I added some additional resources, feel free to suggest others/more if needed Co-authored-by: Jovi De Croock <[email protected]>
1 parent e6cd9fc commit 584550a

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed

website/pages/docs/_meta.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const meta = {
2020
'oneof-input-objects': '',
2121
'defer-stream': '',
2222
'resolver-anatomy': '',
23+
'graphql-errors': '',
2324
'-- 3': {
2425
type: 'separator',
2526
title: 'FAQ',

website/pages/docs/graphql-errors.mdx

+188
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
---
2+
title: Understanding GraphQL.js Errors
3+
---
4+
5+
# Understanding GraphQL.js Errors
6+
7+
When executing a GraphQL operation, a server might encounter problems, such as failing to fetch
8+
data, encountering invalid arguments, or running into unexpected internal issues. Instead of
9+
crashing or halting execution, GraphQL.js collects these problems as structured errors
10+
and includes them in the response.
11+
12+
This guide explains how GraphQL.js represents errors internally, how errors propagate through a
13+
query, and how you can customize error behavior.
14+
15+
## How GraphQL.js represents errors in a response
16+
17+
If an error occurs during execution, GraphQL.js includes it in a top-level `errors` array in the
18+
response, alongside any successfully returned data.
19+
20+
For example:
21+
22+
```json
23+
{
24+
"data": {
25+
"user": null
26+
},
27+
"errors": [
28+
{
29+
"message": "User not found",
30+
"locations": [{ "line": 2, "column": 3 }],
31+
"path": ["user"]
32+
}
33+
]
34+
}
35+
```
36+
37+
Each error object can include the following fields:
38+
39+
- `message`: A human-readable description of the error.
40+
- `locations` (optional): Where the error occurred in the operation.
41+
- `path` (optional): The path to the field that caused the error.
42+
- `extensions` (optional): Additional error metadata, often used for error codes, HTTP status
43+
codes or debugging information.
44+
45+
The GraphQL specification only requires the `message` field. All others are optional, but
46+
recommended to help clients understand and react to errors.
47+
48+
## Creating and handling errors with `GraphQLError`
49+
50+
Internally, GraphQL.js represents errors with the `GraphQLError` class, found in the
51+
`graphql/error` module.
52+
53+
You can create a `GraphQLError` manually:
54+
55+
```js
56+
import { GraphQLError } from 'graphql';
57+
58+
throw new GraphQLError('Something went wrong');
59+
```
60+
61+
To provide more context about an error, you can pass additional options:
62+
63+
```js
64+
throw new GraphQLError('Invalid input', {
65+
nodes,
66+
source,
67+
positions,
68+
path,
69+
originalError,
70+
extensions,
71+
});
72+
```
73+
74+
Each option helps tie the error to specific parts of the GraphQL execution:
75+
76+
- `nodes`: The AST nodes associated with the error.
77+
- `source` and `positions`: The source document and character offsets.
78+
- `path`: The field path leading to the error.
79+
- `originalError`: The underlying JavaScript error, if available.
80+
- `extensions`: Any custom metadata you want to include.
81+
82+
When a resolver throws an error:
83+
84+
- If the thrown value is already a `GraphQLError`, GraphQL.js uses it as-is.
85+
- If it is another type of error (such as a built-in `Error`), GraphQL.js wraps it into a
86+
`GraphQLError`.
87+
88+
This ensures that all errors returned to the client follow a consistent structure.
89+
90+
## How errors propagate during execution
91+
92+
Errors in GraphQL don't necessarily abort the entire operation. How an error affects the response
93+
depends on the nullability of the field where the error occurs.
94+
95+
- **Nullable fields**: If a resolver for a nullable field throws an error, GraphQL.js records
96+
the error and sets the field's value to `null` in the `data` payload.
97+
- **Non-nullable fields**: If a resolver for a non-nullable field throws an error, GraphQL.js
98+
records the error and then sets the nearest parent nullable field to `null`.
99+
100+
For example, consider the following schema:
101+
102+
```graphql
103+
type Query {
104+
user: User
105+
}
106+
107+
type User {
108+
id: ID!
109+
name: String!
110+
}
111+
```
112+
113+
If the `name` resolver throws an error during execution:
114+
115+
- Because `name` is non-nullable (`String!`), GraphQL.js can't return `null` for just that field.
116+
- Instead, the `user` field itself becomes `null`.
117+
- The error is recorded and included in the response.
118+
119+
The result looks like:
120+
121+
```json
122+
{
123+
"data": {
124+
"user": null
125+
},
126+
"errors": [
127+
{
128+
"message": "Failed to fetch user's name",
129+
"path": ["user", "name"]
130+
}
131+
]
132+
}
133+
```
134+
135+
This behavior ensures that non-nullability guarantees are respected even in the presence of errors.
136+
137+
For more detailed rules, see the [GraphQL Specification on error handling](https://spec.graphql.org/October2021/#sec-Errors).
138+
139+
## Customizing errors with `extensions`
140+
141+
You can add additional information to errors using the `extensions` field. This is useful for
142+
passing structured metadata like error codes, HTTP status codes, or debugging hints.
143+
144+
For example:
145+
146+
```js
147+
throw new GraphQLError('Unauthorized', {
148+
extensions: {
149+
code: 'UNAUTHORIZED',
150+
http: {
151+
status: 401
152+
}
153+
}
154+
});
155+
```
156+
157+
Clients can inspect the `extensions` field instead of relying on parsing `message` strings.
158+
159+
Common use cases for `extensions` include:
160+
161+
- Assigning machine-readable error codes (`code: 'BAD_USER_INPUT'`)
162+
- Specifying HTTP status codes
163+
- Including internal debug information (hidden from production clients)
164+
165+
Libraries like [Apollo Server](https://www.apollographql.com/docs/apollo-server/data/errors/) and
166+
[Envelop](https://the-guild.dev/graphql/envelop/plugins/use-error-handler) offer conventions for
167+
structured error extensions, if you want to adopt standardized patterns.
168+
169+
## Best practices for error handling
170+
171+
- Write clear, actionable messages. Error messages should help developers understand what went
172+
wrong and how to fix it.
173+
- Use error codes in extensions. Define a set of stable, documented error codes for your API
174+
to make client-side error handling easier.
175+
- Avoid leaking internal details. Do not expose stack traces, database errors, or other
176+
sensitive information to clients.
177+
- Wrap unexpected errors. Catch and wrap low-level exceptions to ensure that all errors passed
178+
through your GraphQL server follow the `GraphQLError` structure.
179+
180+
In larger servers, you might centralize error handling with a custom error formatting function
181+
to enforce these best practices consistently.
182+
183+
## Additional resources
184+
185+
- [GraphQLError reference](https://graphql.org/graphql-js/error/#graphqlerror)
186+
- [GraphQL Specification: Error handling](https://spec.graphql.org/October2021/#sec-Errors)
187+
- [Apollo Server: Error handling](https://www.apollographql.com/docs/apollo-server/data/errors/)
188+
- [Envelop: Error plugins](https://the-guild.dev/graphql/envelop/plugins/use-error-handler)

0 commit comments

Comments
 (0)