Skip to content

GraphQL Errors

In the previous lesson we saw that a response can carry an errors array. Now we open that array up. Every entry in it is a structured object with a fixed set of keys, and learning to read those keys turns a vague “something broke” into a precise “this field, at this position in your query, failed for this reason.”

Each element of errors has one required key and several optional ones the specification defines:

  • message — a human-readable string describing what went wrong. This is the only mandatory key.
  • locations — a list of { line, column } positions pointing at the exact place in the query text that triggered the error.
  • path — a list of field names and list indices tracing from the root of the response down to the field that failed, for example ["currentTrack", "title"].
  • extensions — a map for machine-readable detail; we devote the whole next-but-one lesson to it.

message is for humans; locations and path are for tools and clients that need to react programmatically. Together they let a client highlight the offending part of the query and route the failure to the right place in its UI.

Not all errors arrive at the same stage. The specification distinguishes two families, and the distinction matters because it decides whether you get any data back at all.

flowchart TD
  Query["Incoming query"]
  Parse["Parse + validate"]
  Exec["Execute resolvers"]
  ReqErr["Request error: errors only, NO data key"]
  FieldErr["Field error: data present (field null) + errors"]
  OK["Success: data only"]
  Query --> Parse
  Parse -->|"fails"| ReqErr
  Parse -->|"passes"| Exec
  Exec -->|"resolver throws"| FieldErr
  Exec -->|"all resolve"| OK
Request errors stop before execution; field errors happen during it.

Request errors happen before execution begins. The query failed to parse, or it parsed but did not validate against the schema — an unknown field, a wrong argument type, a malformed selection. Because execution never started, the response has no data key at all (not even null); it carries only errors.

Field errors (also called execution errors) happen during execution, when a resolver throws or returns an invalid value. By the time one of these fires, the server is already building data, so the response includes data with the failed field nulled out, alongside an errors entry for it. This is the partial-success case we will study in depth next lesson.

The runner below runs two operations against the same schema. The first asks for a field that does not exist — a validation failure, so it is a request error with no data. The second runs a valid query whose resolver throws — a field error, so data comes back with the failed field as null. Compare the two outputs.

JavaScript

Look at the first block: there is no data key, only errors, and the entry carries locations pointing at where ghostField appeared in the query. Now the second block: data is present with nowPlaying set to null, and the matching error carries a path of ["nowPlaying"] so a client knows exactly which field went missing. Same errors array, two very different situations — and you can tell them apart by whether data exists.

Which key is the only required key on a GraphQL error entry?
What does the path key on an error entry describe?
A query references a field that does not exist on the type. What does the response look like?
A valid query runs but one resolver throws. The response will: