Error Handling

Error Handling

Overview

The GraphQL API returns errors in a standard format. Understanding error responses helps you build robust integrations.

Error Response Structure

GraphQL errors appear in the errors array of the response:

{
  "errors": [
    {
      "message": "Error description",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["fieldName"],
      "extensions": {
        "code": "ERROR_CODE",
        "additionalInfo": "..."
      }
    }
  ],
  "data": null
}

Common Error Types

Syntax Errors

Invalid GraphQL syntax:

{
  "errors": [{
    "message": "Syntax Error: Expected Name, found }",
    "locations": [{ "line": 3, "column": 5 }]
  }]
}

Field Errors

Querying fields that don't exist:

{
  "errors": [{
    "message": "Cannot query field \"invalidField\" on type \"Product\"",
    "locations": [{ "line": 4, "column": 7 }]
  }]
}

Authentication Errors

Missing or invalid credentials:

{
  "errors": [{
    "message": "Authentication required",
    "extensions": { "code": "UNAUTHENTICATED" }
  }]
}

Permission Errors

Insufficient permissions for requested data:

{
  "errors": [{
    "message": "Insufficient permissions to access this resource",
    "extensions": { "code": "FORBIDDEN" }
  }]
}

Validation Errors

Invalid argument values:

{
  "errors": [{
    "message": "Invalid value for argument 'first': must be positive integer",
    "path": ["productViewConnection"]
  }]
}

Partial Success

GraphQL can return partial results with errors:

{
  "data": {
    "orderViewConnection": {
      "edges": [...]
    }
  },
  "errors": [{
    "message": "Could not resolve field 'customer'",
    "path": ["orderViewConnection", "edges", 0, "node", "customer"]
  }]
}

In this case:

  • data contains successful parts of the query
  • errors describes what failed
  • Check both fields in your client code

Best Practices

1. Always Check for Errors

const response = await fetch('/graphql', { ... })
const json = await response.json()

if (json.errors) {
  console.error('GraphQL errors:', json.errors)
  // Handle errors appropriately
}

if (json.data) {
  // Process successful data
}

2. Handle HTTP Status Codes

  • 200 OK - Request processed (but may contain GraphQL errors)
  • 400 Bad Request - Invalid GraphQL request
  • 401 Unauthorized - Authentication failed
  • 500 Internal Server Error - Server error

3. Implement Retry Logic

For transient errors:

async function queryWithRetry(query, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await executeQuery(query)
      if (!response.errors || !isTransientError(response.errors)) {
        return response
      }
    } catch (error) {
      if (i === maxRetries - 1) throw error
    }
    await sleep(Math.pow(2, i) * 1000) // Exponential backoff
  }
}

4. Log Error Details

Include in logs:

  • Error messages
  • Query that caused the error
  • Variables used
  • User/session context
  • Timestamp

5. Graceful Degradation

Design UI to handle:

  • Missing optional fields
  • Partial data availability
  • Permission-restricted fields

Testing Error Scenarios

Test your error handling with:

# Test invalid field
query {
  productViewConnection(first: 10) {
    edges {
      node {
        invalidFieldName
      }
    }
  }
}

# Test invalid argument
query {
  productViewConnection(first: -10) {
    edges {
      node {
        productId
      }
    }
  }
}