Errors and partial results

GraphQL · Practical · 12 min

GraphQL responses can be partly successful, and clients must handle that correctly.

A GraphQL response can contain both data and errors. Each error has a message, usually locations and a path to the field that failed, plus optional extensions for machine-readable codes (e.g. {"code": "FORBIDDEN"}).

When a resolver throws, the executor records an error and sets that field to null. If the field is nullable, the rest of the response survives. If it is non-null, the null propagates to the nearest nullable parent, erasing the siblings too; if nothing is nullable all the way up, data itself becomes null.

That is why nullability is a design decision:

  • Nullable fields isolate failures (a broken recommendations service does not kill the page).
  • Non-null fields simplify client code but widen the blast radius of an error.

Two categories of errors:

  • Request errors (syntax, validation, bad variables): nothing executes; the response has errors and no data key.
  • Field errors during execution: partial data plus errors.

For expected domain outcomes ("email taken", "not found"), many teams return typed results instead, e.g. a union CreateUserResult = User | EmailTaken, so clients handle them with full type safety. Do not leak stack traces or internal messages: mask unexpected errors in production.

Example

import { buildSchema, graphql } from "graphql";
const schema = buildSchema(`
  type Profile { name: String!  recommendations: [String!] }
  type Query { me: Profile }
`);
const rootValue = {
  me: () => ({
    name: "Ann",
    recommendations: () => { throw new Error("recs service down"); },
  }),
};
const res = await graphql({ schema, rootValue, source: "{ me { name recommendations } }" });
console.log(JSON.stringify(res.data));
// {"me":{"name":"Ann","recommendations":null}}
console.log(res.errors[0].message, res.errors[0].path);
// recs service down [ 'me', 'recommendations' ]

Remember

  • Errors carry message, locations, path and optional extensions
  • A null in a non-null field bubbles up to the nearest nullable parent
  • Model expected outcomes as types; reserve errors for failures

Watch out for

  • Clients that ignore errors whenever data is present and silently show incomplete screens.

Check yourself

  1. `recommendations` were `[String!]!` instead of `[String!]` and its resolver throws. What happens to `me`?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: graphql.org/learn/response/