Skip to content

Errors & Validation

Most APIs treat failure as a separate channel: a 404, a 500, a body you parse differently when things go wrong. GraphQL takes a different stance. A single response can describe both what succeeded and what failed, in one shape, at the same time. That shape is the heart of this module.

A GraphQL response is a JSON object with up to three top-level keys: data, errors, and extensions. The first holds whatever the server managed to resolve. The second is a list of everything that went wrong. They are not mutually exclusive — a response can carry a filled-out data tree and a non-empty errors array at once.

We have called the schema a contract throughout this course. Errors are written into that contract too. The specification fixes the shape of an error object, the rules for where null may appear when a field fails, and the guarantee that a transport-level success (an HTTP 200) can still wrap a failed operation. Clients are expected to read errors, not just data.

This is liberating once you internalize it. You stop thinking “did the request succeed?” as a yes/no question and start thinking “which parts succeeded, which parts failed, and what does each failure tell the client to do?” A good GraphQL API answers all three in one round trip.

flowchart TD
  Response["GraphQL response (JSON)"]
  Data["data — what resolved"]
  Errors["errors — list of failures"]
  Extensions["extensions — optional metadata"]
  Response --> Data
  Response --> Errors
  Response --> Extensions
  Errors -->|"path"| Data
A GraphQL response splits into data, errors, and optional extensions.

The diagram shows the three branches. data mirrors the shape of the query. errors is a flat list, where each entry points back into data with a path. extensions is a free-form bag the server may use to attach machine-readable detail — we will spend a whole lesson on it.

This module is about the failure side of the contract. The five lessons are:

  1. Errors & Validation (you are here) — the data/errors response shape and why errors are first-class.
  2. GraphQL Errors — the errors array in detail: message, locations, path, and request errors vs field errors.
  3. Partial Results — how nullability controls error propagation, letting siblings resolve while one field fails.
  4. Error Extensions — typed errors with extensions, throwing GraphQLError, and masking internals in production.
  5. Input Validation — what the schema validates for free vs business rules you enforce in resolvers.

Enough theory. The runner below defines a one-field schema whose resolver throws. Press Run and read the result: notice that data is present (it is null for the failed field) and errors describes what happened.

JavaScript

Read the output as one object. data.currentTrack came back null because its resolver threw and the field was nullable. Alongside it, errors holds a single entry describing the failure. Neither key cancels the other out — that coexistence is exactly what makes GraphQL error handling different from a plain HTTP status code.

Which top-level keys can a single GraphQL response contain?
Can a response carry both a populated data tree and a non-empty errors array?
In the contract, errors are best described as: