Handling Errors and Response Codes
Understanding how Common Ground APIs handle errors and response codes is crucial for building robust applications. This guide explains the GraphQL error model, HTTP status codes, and best practices for error handling.
GraphQL Error Model
GraphQL Returns 200 Status Code
Unlike REST APIs, GraphQL typically returns HTTP status code
200 OKeven when errors occur. Errors are included in the response body within anerrorsarray, while successful data appears in thedatafield.
This is a fundamental aspect of GraphQL's design: the HTTP status code indicates whether the request was successfully received and processed by the server, not whether the operation succeeded. The response body tells you the actual result.
Response Structure
A GraphQL response always has this structure:
{
"data": { ... },
"errors": [ ... ]
}
Successful Response:
{
"data": {
"items": [
{ "_id": "123", "title": "Item 1" }
]
}
}
Response with Errors:
{
"data": null,
"errors": [
{
"message": "Authentication error",
"extensions": {
"code": "UNAUTHENTICATED"
},
"path": ["items"]
}
]
}
Partial Success (Some Fields Failed):
{
"data": {
"items": [
{ "_id": "123", "title": "Item 1" }
],
"user": null
},
"errors": [
{
"message": "User not found",
"path": ["user"]
}
]
}
HTTP Status Codes
While GraphQL operations typically return 200 OK, certain HTTP status codes are used for specific scenarios:
200 OK
When it's used:
- Successful GraphQL queries and mutations
- GraphQL operations with errors (errors are in the response body)
What to check:
- Always inspect the
errorsarray in the response body - Check the
datafield for successful results - Even with
200 OK, the operation may have failed
400 Bad Request
When it's used:
- Invalid GraphQL query syntax
- Malformed request body
- Missing required headers
- Invalid JSON in request body
- Request body too large
What it means: The request itself is invalid and cannot be processed. This typically happens before the GraphQL query is executed.
Common causes:
- Syntax errors in GraphQL query
- Missing or invalid
Content-Type: application/jsonheader - Invalid JSON structure
- Request exceeds size limits
Example:
// Invalid GraphQL syntax
const query = `
query {
items { // Missing closing brace
`;
// This will return 400 Bad Request
How to handle:
- Validate your GraphQL queries before sending
- Ensure proper JSON formatting
- Check request headers
- Verify request body size
401 Unauthorized
When it's used:
- Missing authentication credentials
- Invalid authentication token
- Expired authentication token
In GraphQL, authentication errors are often returned as
200 OKwith an error in the response body. However, if authentication fails at the HTTP middleware level (before the GraphQL layer), you may receive401.
404 Not Found
When it's used:
- Requesting a non-existent endpoint (not
/graphql) - Invalid API route
This is rare for GraphQL endpoints. If you're hitting
/graphql, you should get200 OKeven with errors.
429 Too Many Requests
When it's used:
- Rate limit exceeded
- Too many requests in a time window
What to do:
- Implement exponential backoff
- Respect rate limit headers if provided
- Reduce request frequency
- Check your rate limit tier
500 Internal Server Error
When it's used:
- Server-side errors that prevent request processing
- Database connection failures
- Unexpected server crashes
- Errors in server middleware (before GraphQL execution)
Most GraphQL errors are returned as
200 OKwith error details.500typically indicates a problem before GraphQL execution.
How to handle:
- Retry with exponential backoff
- Log the error for investigation
- Contact support if persistent
GraphQL Error Types
Error Structure
Each error in the errors array has this structure:
{
message: string; // Human-readable error message
locations?: Array<{ // Where in the query the error occurred
line: number;
column: number;
}>;
path?: Array<string | number>; // Path to the field that errored
extensions?: { // Additional error information
code: string; // Error code (e.g., "UNAUTHENTICATED")
[key: string]: any; // Additional custom fields
};
}
Common Error Codes
UNAUTHENTICATED
Code: UNAUTHENTICATED
When it occurs:
- No user session found
- Missing authentication context
- Invalid or expired session
HTTP Status: Usually 200 OK (error in response body)
Example:
{
"data": null,
"errors": [
{
"message": "Authentication error",
"extensions": {
"code": "UNAUTHENTICATED"
}
}
]
}
How to handle:
- Check if user is logged in
- Refresh authentication token
- Redirect to login page
- Retry request after authentication
UNAUTHORIZED
Code: UNAUTHORIZED
When it occurs:
- User is authenticated but lacks required permissions
- Insufficient role or access level
- Operation not allowed for current user
HTTP Status: Usually 200 OK (error in response body)
Example:
{
"data": null,
"errors": [
{
"message": "Unauthorized",
"extensions": {
"code": "UNAUTHORIZED"
}
}
]
}
How to handle:
- Check user permissions
- Verify required role/access level
- Show appropriate error message to user
- Hide UI elements that require higher permissions
Validation Errors
Code: Various (often no specific code)
When it occurs:
- Invalid input values
- Missing required fields
- Field value constraints violated
- Type mismatches
HTTP Status: Usually 200 OK (error in response body)
Example:
{
"data": null,
"errors": [
{
"message": "Invalid pagination: page must be greater than 0",
"path": ["items"],
"extensions": {
"code": "BAD_USER_INPUT"
}
}
]
}
How to handle:
- Validate input on client side before sending
- Display validation errors to users
- Highlight invalid fields in forms
- Provide clear error messages
Not Found Errors
Code: Various (often no specific code)
When it occurs:
- Requested resource doesn't exist
- Invalid ID provided
- Resource was deleted
HTTP Status: Usually 200 OK (error in response body)
Example:
{
"data": {
"item": null
},
"errors": [
{
"message": "Item not found",
"path": ["item"]
}
]
}
How to handle:
- Check if resource exists before displaying
- Show "not found" message to user
- Redirect to appropriate page
- Handle gracefully in UI
Best Practices
- Always check for errors - Even when you receive
200 OK, check theerrorsarray in the response body - Check HTTP status before parsing - Validate HTTP status before attempting to parse JSON to catch network-level errors
- Handle partial success - GraphQL allows partial data. Some fields may succeed while others fail. Check both
dataanderrorsin responses - Differentiate error types - Handle errors based on
extensions.code(e.g.,UNAUTHENTICATED,UNAUTHORIZED,BAD_USER_INPUT) to provide appropriate user feedback - Implement retry logic - For transient errors (network issues, rate limits), implement retry logic with exponential backoff
- Log errors appropriately - Log different error types with appropriate detail levels for debugging
- Provide user-friendly messages - Transform technical error messages into user-friendly ones for end users
Error Handling Patterns
Try-Catch with Status Check
Wrap GraphQL requests in a try-catch block to handle both HTTP-level and GraphQL-level errors. Check the HTTP response status using response.ok to catch network errors, rate limits, and authentication failures that occur before GraphQL execution. Then parse the JSON response and check for GraphQL errors in the errors array. Handle GraphQL errors and network errors separately—GraphQL errors contain detailed error information in the response body, while network errors indicate connection or HTTP-level issues.
Apollo Client Error Handling
Apollo Client provides an error link that automatically intercepts and handles errors. Use the onError function to create an error link that receives graphQLErrors and networkError separately. GraphQL errors include error codes in extensions.code (such as UNAUTHENTICATED or UNAUTHORIZED) that you can use to handle specific error types. Network errors include HTTP status codes (like 429 for rate limits) that you can check to implement appropriate handling. Add the error link to your Apollo Client configuration using from([errorLink, httpLink]) to enable automatic error handling across all requests.
Summary
Key Takeaways
- GraphQL returns
200 OKeven with errors - Always check theerrorsarray in the response body - 400-range HTTP errors indicate invalid requests (malformed queries, missing headers, etc.)
- GraphQL errors are in the response body - Check
result.errorseven when HTTP status is 200 - Partial success is possible - Some fields may succeed while others fail
- Error codes in extensions - Use
extensions.codeto identify error types - Differentiate error types - Handle authentication, authorization, validation, and server errors differently
Quick Reference
| HTTP Status | Meaning | When to Check |
|---|---|---|
200 OK | Request processed | Always check errors array |
400 Bad Request | Invalid request | Before sending (validate query) |
401 Unauthorized | Missing/invalid auth | Check authentication |
429 Too Many Requests | Rate limit exceeded | Implement backoff |
500 Internal Server Error | Server error | Retry with backoff |
Common Error Codes
UNAUTHENTICATED- User not logged inUNAUTHORIZED- Insufficient permissionsBAD_USER_INPUT- Invalid input values- (No code) - Generic errors, check message