Handling operation errors
Apollo Client can encounter a variety of errors when executing operations on your GraphQL server. Apollo Client helps you handle these errors according to their type, enabling you to show appropriate information to the user when an error occurs.
Error types
Executing GraphQL operations on a remote server can result in GraphQL errors or network errors.
GraphQL errors
These are errors related to the server-side execution of a GraphQL operation. They include:
Syntax errors (e.g., a query was malformed)
Validation errors (e.g., a query included a schema field that doesn't exist)
Resolver errors (e.g., an error occurred while attempting to populate a query field)
If a syntax error or validation error occurs, your server doesn't execute the operation at all because it's invalid. If resolver errors occur, your server can still return partial data.
Learn more about GraphQL errors in the Apollo Server documentation.
If a GraphQL error occurs, your server includes it in the errors
array of its response to Apollo Client:
Example error response
1{
2 "errors": [
3 {
4 "message": "Cannot query field \"nonexistentField\" on type \"Query\".",
5 "locations": [
6 {
7 "line": 2,
8 "column": 3
9 }
10 ],
11 "extensions": {
12 "code": "GRAPHQL_VALIDATION_FAILED",
13 "exception": {
14 "stacktrace": [
15 "GraphQLError: Cannot query field \"nonexistentField\" on type \"Query\".",
16 "...additional lines..."
17 ]
18 }
19 }
20 }
21 ],
22 "data": null
23}
Apollo Client then adds those errors to the error.graphQLErrors
array returned by your useQuery
call (or whichever operation hook you used).
If a GraphQL error prevents Apollo Server from executing your operation at all, it responds with a 4xx
status code. Apollo Server responds with a 200
status code if resolver errors occurred but the response still includes partial data.
Partial data with resolver errors
An operation that produces resolver errors might also return partial data. This means that some (but not all) of the data your operation requested is included in your server's response. Apollo Client ignores partial data by default, but you can override this behavior by setting a GraphQL error policy.
Network errors
These are errors encountered while attempting to communicate with your GraphQL server, usually resulting in a 4xx
or 5xx
response status code (and no data).
When a network error occurs, Apollo Client adds it to the error.networkError
field returned by your useQuery
call (or whichever operation hook you used).
You can add retry logic and other advanced network error handling to your application with Apollo Link.
GraphQL error policies
If a GraphQL operation produces one or more resolver errors, your server's response might still include partial data in the data
field:
1{
2 "data": {
3 "getInt": 12,
4 "getString": null
5 },
6 "errors": [
7 {
8 "message": "Failed to get string!"
9 // ...additional fields...
10 }
11 ]
12}
By default, Apollo Client throws away partial data and populates the error.graphQLErrors
array of your useQuery
call (or whichever hook you're using). You can instead use these partial results by defining an error policy for your operation.
Apollo Client supports the following error policies for an operation:
Policy | Description |
---|---|
none | If the response includes GraphQL errors, they are returned on error.graphQLErrors and the response data is set to undefined even if the server returns data in its response. This means network errors and GraphQL errors result in a similar response shape. This is the default error policy. |
ignore | graphQLErrors are ignored (error.graphQLErrors is not populated), and any returned data is cached and rendered as if no errors occurred. |
all | Both data and error.graphQLErrors are populated, enabling you to render both partial results and error information. |
Setting an error policy
Specify an error policy in the options object you provide your operation hook (such as useQuery
), like so:
1const MY_QUERY = gql`
2 query WillFail {
3 badField # This field's resolver produces an error
4 goodField # This field is populated successfully
5 }
6`;
7
8function ShowingSomeErrors() {
9 const { loading, error, data } = useQuery(MY_QUERY, { errorPolicy: "all" });
10
11 if (loading) return <span>loading...</span>;
12 return (
13 <div>
14 <h2>Good: {data.goodField}</h2>
15 <pre>
16 Bad:{" "}
17 {error.graphQLErrors.map(({ message }, i) => (
18 <span key={i}>{message}</span>
19 ))}
20 </pre>
21 </div>
22 );
23}
This example uses the all
error policy to render both partial data and error information whenever applicable.
Advanced error handling with Apollo Link
The Apollo Link library enables you to configure advanced handling of errors that occur while executing GraphQL operations.
As a recommended first step, you can add an onError
link to your link chain that receives error details and acts on them accordingly.
The example below passes the ApolloClient
constructor a link chain with two links:
An
onError
link that checks forgraphQLErrors
or anetworkError
in the server's response. It logs the details of whichever error(s) it finds.An
HttpLink
that sends each GraphQL operation to your server.This is the chain's terminating link.
Click to expand example
1import { ApolloClient, HttpLink, InMemoryCache, from } from "@apollo/client";
2import { onError } from "@apollo/client/link/error";
3
4const errorLink = onError(({ graphQLErrors, networkError }) => {
5 if (graphQLErrors)
6 graphQLErrors.forEach(({ message, locations, path }) =>
7 console.log(
8 `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
9 )
10 );
11 if (networkError) console.error(`[Network error]: ${networkError}`);
12});
13
14const httpLink = new HttpLink({ uri: 'http://localhost:4000/graphql' })
15
16const client = new ApolloClient({
17 cache: new InMemoryCache(),
18 link: from([errorLink, httpLink]),
19});
Retrying operations
Apollo Link helps you retry failed operations that might be resolved by a followup attempt. We recommend different links depending on the type of error that occurred:
The
onError
link for GraphQL errorsThe
RetryLink
for network errors
On GraphQL errors
The onError
link can retry a failed operation based on the type of GraphQL error that's returned. For example, when using token-based authentication, you might want to automatically handle re-authentication when the token expires.
To retry an operation, you return forward(operation)
in your onError
function. Here's an example:
1onError(({ graphQLErrors, networkError, operation, forward }) => {
2 if (graphQLErrors) {
3 for (let err of graphQLErrors) {
4 switch (err.extensions.code) {
5 // Apollo Server sets code to UNAUTHENTICATED
6 // when an AuthenticationError is thrown in a resolver
7 case "UNAUTHENTICATED":
8 // Modify the operation context with a new token
9 const oldHeaders = operation.getContext().headers;
10 operation.setContext({
11 headers: {
12 ...oldHeaders,
13 authorization: getNewToken(),
14 },
15 });
16 // Retry the request, returning the new observable
17 return forward(operation);
18 }
19 }
20 }
21
22 // To retry on network errors, we recommend the RetryLink
23 // instead of the onError link. This just logs the error.
24 if (networkError) {
25 console.log(`[Network error]: ${networkError}`);
26 }
27});
If your retried operation also results in errors, those errors are not passed to your
onError
link to prevent an infinite loop of operations. This means that anonError
link can retry a particular operation only once.
If you don't want to retry an operation, your onError
link's function should return nothing.
On network errors
To retry operations that encounter a network error, we recommend adding a RetryLink
to your link chain. This link enables you to configure retry logic like exponential backoff and total number of attempts.
See the documentation for RetryLink
.
onError
link options
See the onError
API reference.