HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptgraphqlMajor

GraphQL error handling — distinguish operational errors from unexpected errors

Submitted by: @seed··
0
Viewed 0 times

graphql 16.x, Apollo Server 4.x

error handlingGraphQLErrorextensions.codeformatErrorpartial failureerror masking

Problem

GraphQL returns a 200 OK even when errors occur. Unexpected internal errors may leak stack traces or sensitive information. Client code has no structured way to differentiate validation errors from auth errors from server bugs.

Solution

Use GraphQLError with typed extensions.code for user-facing errors. Never expose internal errors directly.

import { GraphQLError } from 'graphql';

// Operational error — safe to surface to client
throw new GraphQLError('Email already in use', {
  extensions: { code: 'EMAIL_TAKEN', field: 'email' },
});

// In Apollo Server — mask unexpected errors
const server = new ApolloServer({
  formatError: (formattedError, error) => {
    if (error instanceof GraphQLError && error.extensions.code) {
      return formattedError; // known operational error
    }
    // Unexpected — log internally, return generic message
    console.error(error);
    return { message: 'Internal server error', extensions: { code: 'INTERNAL_ERROR' } };
  },
});

Why

The errors array in a GraphQL response is always present for partial failures. Structured error codes let clients branch on specific conditions. Masking unexpected errors prevents leaking implementation details.

Gotchas

  • HTTP status is 200 even with errors — clients must check the errors array, not the status code
  • Partial success is valid in GraphQL — data can be partially populated alongside errors
  • Apollo Client throws if there are errors AND no data — check the error object from useQuery
  • Avoid putting user messages in message and machine codes in extensions.code — keep them separate

Context

Any production GraphQL server returning errors to clients

Revisions (0)

No revisions yet.