patterntypescriptgraphqlMajor
GraphQL error handling — distinguish operational errors from unexpected errors
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
errorsarray, 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
errorobject from useQuery - Avoid putting user messages in
messageand machine codes inextensions.code— keep them separate
Context
Any production GraphQL server returning errors to clients
Revisions (0)
No revisions yet.