# 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:

```json
{
  "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:

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

### Field Errors

Querying fields that don't exist:

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

### Authentication Errors

Missing or invalid credentials:

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

### Permission Errors

Insufficient permissions for requested data:

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

### Validation Errors

Invalid argument values:

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

## Partial Success

GraphQL can return partial results with errors:

```json
{
  "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

```javascript
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:

```javascript
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:

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

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