Error handling in GraphQL is different on both server and client side tooling. You no longer are looking at HTTP status codes to debug what went wrong for the request made. This makes one more involved in debugging errors, but thankfully there’s a structure to the errors in GraphQL and we will look into it to see how to debug and fix them.
Let’s take a typical GraphQL query:
query {
author {
id
name
}
}
The response of the above query can have the following objects:
{
"data": [{ id: 1, name: "Praveen"}],
"errors": []
}
Top Level Errors Object in GraphQL Responses
When the response contains the errors
object along with the data
object, it could mean a partially correct response for the request. Digging into the errors object will give a better idea into what part of the query went wrong.
Identifying error types will help quickly fix them. Clients can encounter these types of errors while communicating with the GraphQL server.
Server Problems / Network errors
All the errors above come under the category of GraphQL errors with a response status code of 200
. When there is a network error while trying to contact a GraphQL server, due to either the server being down or timeouts etc, then the response will be a status code of 4xx or 5xx.
If the server responds anything other than 200, the response is not successful due to either being a:
- Bad request (400)
- Unauthorized (401)
- Gateway errors (5xx)
These are non-ideal scenarios where the original response couldn’t be delivered via 200 (despite there is a possibility of a request containing an error). This non-standard response needs to be checked with the server for underlying issue like network errors etc.
Client side problems — Validation rules of GraphQL Query
GraphQL is strongly typed and it performs validation of all queries before executing them. It can reject a query if it is invalid based on a set of rules.
The validation rules could again be split into
- malformed query
- syntax or schema logic
- variables and fragments not defined properly.
For example:
{
"errors": [
{
"extensions": {
"path": "$.variableValues",
"code": "validation-failed"
},
"message": "unexpected variables in variableValues: products"
}
]
}
This is a typical error that you get when a client makes a request with a variable that has not been defined. A common nightmare when using GUI tools like GraphiQL where the variables UI has remnants of variable usage from previous queries.
Read the source code for validation rules in graphql-js server to understand various query validation that goes through before executing the query.
Do note that validation errors never return any data to the client, the execution errors have the ability to return partial data sets. The operation could have been largely fulfilled but due to slow performance of a specific field or specific part of the query, it could result in partial data set.
Top-level errors
The default errors JSON includes message
, locations
and path
. According to the working draft of the spec, it is also possible to send custom data in the extensions
key.
Field level errors
{
“errors”: [{
“extensions”: {
“path”: “$.selectionSet.dogs.selectionSet.name”,
“code”: “validation-failed”
},
“message”: “field \”name\” not found in type: ‘dogs’”
}]
}
In the above response, you can see the extensions
key inside errors
object that contains more metadata on what went wrong. Technically this error came out of using a field which doesn't exist (either due to Auth or schema not really having the field).
GraphQL Subscription Errors
Another common set of errors typically encountered while connecting with GraphQL servers comes when connecting to websocket connections for realtime subscriptions:
- websocket connection could not be initalised. This needs a check with the URL of the websocket connection; note that websocket URLs start with
ws
orwss
and nothttps
. - invalid http upgrade (this could happen when http(s) is used for a websocket connection and the right connection split is not configured for ws)
- connectionParams not passed for authorization headers. If you are using a JWT token, it needs to be passed via connectionParams using the GraphQL Client.
Resources
Originally published at https://hasura.io on May 7, 2021.