# Error Handling

Understand and handle API errors effectively.

## Error Response Format

When an error occurs, the API returns a structured error response:


```json
{
  "detail": "Error message describing what went wrong",
  "error_code": "SPECIFIC_ERROR_CODE",
  "field_errors": {
    "field_name": ["Field-specific error message"]
  }
}
```

## HTTP Status Codes

### Client Errors (4xx)

| Code | Error | Meaning |
|  --- | --- | --- |
| `400` | Bad Request | Invalid request format or parameters |
| `401` | Unauthorized | Missing or invalid authentication |
| `403` | Forbidden | Valid auth but insufficient permissions |
| `404` | Not Found | Resource doesn't exist |
| `409` | Conflict | Request conflicts with current state |
| `422` | Unprocessable Entity | Validation error |
| `429` | Too Many Requests | Rate limit exceeded |


### Server Errors (5xx)

| Code | Error | Meaning |
|  --- | --- | --- |
| `500` | Internal Server Error | Something went wrong on our end |
| `502` | Bad Gateway | Temporary service issue |
| `503` | Service Unavailable | Service temporarily unavailable |
| `504` | Gateway Timeout | Request took too long |


## Common Errors

### 400 Bad Request

**Cause**: Malformed JSON or invalid parameters


```json
{
  "detail": "JSON parse error - Expecting value"
}
```

**Solution**: Validate your JSON syntax and request parameters.

### 401 Unauthorized

**Cause**: Missing or invalid API token


```json
{
  "detail": "Authentication credentials were not provided."
}
```

**Solution**: Check that you're including the `Authorization` header with a valid token.

### 403 Forbidden

**Cause**: Insufficient permissions


```json
{
  "detail": "You do not have permission to perform this action."
}
```

**Solution**: Verify your user role has the required permissions for this operation.

### 404 Not Found

**Cause**: Resource doesn't exist


```json
{
  "detail": "Not found."
}
```

**Solution**: Verify the resource ID and ensure it exists.

### 422 Validation Error

**Cause**: Invalid field values


```json
{
  "identifier": ["This field is required."],
  "assessment_type": ["Invalid choice."]
}
```

**Solution**: Review the field errors and fix the invalid values.

### 429 Rate Limit Exceeded

**Cause**: Too many requests


```json
{
  "detail": "Request was throttled. Expected available in 3600 seconds."
}
```

**Solution**: Implement exponential backoff and respect rate limits.

## Error Handling Patterns

### JavaScript/TypeScript


```typescript
async function makeApiCall(url: string) {
  try {
    const response = await fetch(url, {
      headers: {
        'Authorization': `Bearer ${API_TOKEN}`,
        'Content-Type': 'application/json'
      }
    });

    if (!response.ok) {
      const error = await response.json();
      
      switch (response.status) {
        case 400:
          throw new ValidationError(error.detail);
        case 401:
          throw new AuthenticationError('Invalid token');
        case 403:
          throw new PermissionError('Insufficient permissions');
        case 404:
          throw new NotFoundError('Resource not found');
        case 429:
          throw new RateLimitError('Rate limit exceeded');
        default:
          throw new APIError(error.detail);
      }
    }

    return await response.json();
  } catch (error) {
    console.error('API Error:', error);
    throw error;
  }
}
```

### Python


```python
import requests
from requests.exceptions import HTTPError

class APIError(Exception):
    pass

class AuthenticationError(APIError):
    pass

class ValidationError(APIError):
    pass

def make_api_call(url):
    try:
        response = requests.get(
            url,
            headers={
                'Authorization': f'Bearer {API_TOKEN}',
                'Content-Type': 'application/json'
            }
        )
        response.raise_for_status()
        return response.json()
        
    except HTTPError as e:
        status_code = e.response.status_code
        error_data = e.response.json()
        
        if status_code == 401:
            raise AuthenticationError('Invalid token')
        elif status_code == 422:
            raise ValidationError(error_data)
        elif status_code == 429:
            # Implement retry logic
            time.sleep(60)
            return make_api_call(url)
        else:
            raise APIError(error_data.get('detail'))
```

## Retry Logic

### Exponential Backoff

For transient errors (429, 5xx), implement exponential backoff:


```python
import time
from typing import Optional

def make_request_with_retry(
    url: str,
    max_retries: int = 3,
    backoff_factor: int = 2
) -> Optional[dict]:
    
    for attempt in range(max_retries):
        try:
            response = requests.get(url, headers=headers)
            response.raise_for_status()
            return response.json()
            
        except requests.exceptions.HTTPError as e:
            status_code = e.response.status_code
            
            # Don't retry client errors (except rate limit)
            if 400 <= status_code < 500 and status_code != 429:
                raise
            
            # Calculate wait time
            wait_time = backoff_factor ** attempt
            
            if attempt < max_retries - 1:
                print(f"Retry {attempt + 1}/{max_retries} after {wait_time}s")
                time.sleep(wait_time)
            else:
                raise
```

## Validation Errors

Handle field-level validation errors:


```typescript
interface ValidationErrorResponse {
  [field: string]: string[];
}

function handleValidationError(errors: ValidationErrorResponse) {
  const formattedErrors = Object.entries(errors).map(
    ([field, messages]) => ({
      field,
      message: messages.join(', ')
    })
  );
  
  // Display errors to user
  formattedErrors.forEach(({ field, message }) => {
    showFieldError(field, message);
  });
}
```

## Logging & Monitoring

### What to Log

✅ **Do log**:

- Error messages and codes
- Request IDs (if provided)
- Timestamp
- Endpoint and method
- Status code


❌ **Don't log**:

- API tokens
- Sensitive user data
- Personal information


### Example


```javascript
function logApiError(error, context) {
  console.error({
    timestamp: new Date().toISOString(),
    endpoint: context.url,
    method: context.method,
    status: error.status,
    message: error.message,
    // Don't log: token, user data
  });
}
```

## Best Practices

1. **Always check status codes** before processing responses
2. **Implement retry logic** for 429 and 5xx errors
3. **Validate data client-side** before sending to reduce 422 errors
4. **Display user-friendly messages** instead of raw API errors
5. **Monitor error rates** to detect issues early
6. **Cache tokens** to avoid authentication errors
7. **Handle network failures** gracefully


## Need Help?

If you encounter persistent errors:

1. Check [API Status](https://status.coolset.com)
2. Review the [API Reference](/supply-chain-api)
3. Contact [support@coolset.com](mailto:support@coolset.com)


Include these details when reporting errors:

- Timestamp
- Endpoint and method
- Status code and error message
- Request ID (if available)


## Next Steps

- [Quick Start Guide →](/getting-started/quickstart)
- [Authentication →](/getting-started/authentication)
- [Use Cases →](/use-cases/eudr-compliance)