GraphQL in Production · GraphQL Fundamentals for API Designers
Error Handling: errors[] vs Errors as Data
Separate system failures from expected business outcomes.
The GraphQL response has data and errors; errors include message, path, locations and extensions (use extensions.code for machine-readable codes). Use the errors array for unexpected failures (resolver crashed, service down, auth failure). Model expected business outcomes as data: userErrors in payloads or result unions (union CheckoutResult = Order | PaymentDeclined | OutOfStock), which clients must handle explicitly and type-check. GraphQL-over-HTTP defines status codes: 200 for executed operations (even with field errors) using application/graphql-response+json, 4xx for requests that fail validation/parsing.
Ways to model errors
| Criterion | errors[] array | userErrors in payload | Result unions |
|---|---|---|---|
| Best for | Unexpected/system errors | Validation messages | Distinct business outcomes |
| Type-safe on client | No (stringly) | Partly (codes) | Yes (__typename) |
| Partial data | Yes | N/A | N/A |
| Schema overhead | None | Low | Medium |
union CheckoutResult = CheckoutSuccess | PaymentDeclined | OutOfStock
type CheckoutSuccess { order: Order! }
type PaymentDeclined { reason: String! retryable: Boolean! }
type OutOfStock { sku: String! available: Int! }
type Mutation { checkout(input: CheckoutInput!): CheckoutResult! }
# Client
mutation { checkout(input: {...}) {
__typename
... on CheckoutSuccess { order { id } }
... on PaymentDeclined { reason retryable }
... on OutOfStock { sku available }
} }
Common pitfalls
- Business outcomes thrown as exceptions clients can't type-check.
- Leaking stack traces in error messages.
- Clients ignoring
errorswhendatais partially present.
Key points
- System errors → errors[] with extensions.code
- Business outcomes → data (userErrors/unions)
- Follow GraphQL-over-HTTP status rules
Further reading: GraphQL spec: Errors
Practice questions
Why model 'payment declined' as data instead of an error?
Answer
It's an expected outcome that clients must handle; as a union member it's typed, discoverable in the schema and forces explicit handling, while errors[] is untyped.
Can a GraphQL response contain both data and errors?
Answer
Yes. Partial success is normal: successfully resolved fields are returned in data, failed ones are null with corresponding entries in errors.
Open in the app to mark lessons complete, take notes and track your progress.