> ## Documentation Index
> Fetch the complete documentation index at: https://docs.humanly.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Best practices for handling API errors and edge cases

## Overview

This guide covers how to handle errors and edge cases when using the Gather API. Proper error handling ensures your integration is robust and provides a good user experience.

## Error Response Format

All errors follow a consistent format:

```json theme={null}
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {
      // Additional error details
    }
  },
  "meta": {
    "requestId": "uuid",
    "timestamp": "2024-01-01T00:00:00Z"
  }
}
```

## HTTP Status Codes

### 400 Bad Request

Invalid request parameters or malformed request body.

```json theme={null}
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request parameters",
    "details": {
      "field": "email",
      "reason": "Invalid email format"
    }
  }
}
```

**Action**: Review the error details and fix the request parameters.

### 401 Unauthorized

Invalid or missing authentication credentials.

```json theme={null}
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or missing authentication credentials"
  }
}
```

**Action**: Verify your API credentials are correct and properly formatted.

### 404 Not Found

Resource not found.

```json theme={null}
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Resource not found",
    "details": {
      "resource": "interview",
      "id": "uuid"
    }
  }
}
```

**Action**: Verify the resource ID exists and you have access to it.

### 429 Too Many Requests

Rate limit exceeded.

```json theme={null}
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Please try again later.",
    "details": {
      "limit": 1000,
      "remaining": 0,
      "resetAt": "2024-01-01T01:00:00Z"
    }
  }
}
```

**Action**: Implement exponential backoff and retry after the reset time.

### 500 Internal Server Error

Server error.

```json theme={null}
{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "An internal error occurred"
  }
}
```

**Action**: Retry the request with exponential backoff. If the error persists, contact support.

## Error Handling Patterns

### Retry Logic

Implement retry logic for transient errors (429, 500):

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    async function makeRequestWithRetry(url, options, maxRetries = 3) {
      for (let i = 0; i < maxRetries; i++) {
        try {
          const response = await fetch(url, options);
          
          if (response.status === 429) {
            const resetTime = parseInt(response.headers.get('X-RateLimit-Reset'));
            const waitTime = Math.max((resetTime * 1000) - Date.now(), 0);
            
            if (i < maxRetries - 1) {
              await new Promise(resolve => setTimeout(resolve, waitTime));
              continue;
            }
          }
          
          if (!response.ok && response.status >= 500 && i < maxRetries - 1) {
            await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
            continue;
          }
          
          return response;
        } catch (error) {
          if (i === maxRetries - 1) throw error;
          await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
        }
      }
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import time
    import requests

    def make_request_with_retry(url, headers, max_retries=3):
        for i in range(max_retries):
            try:
                response = requests.get(url, headers=headers)
                
                if response.status_code == 429:
                    reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
                    wait_time = max(reset_time - int(time.time()), 0)
                    
                    if i < max_retries - 1:
                        time.sleep(wait_time)
                        continue
                
                if response.status_code >= 500 and i < max_retries - 1:
                    time.sleep(2 ** i)
                    continue
                
                return response
            except Exception as e:
                if i == max_retries - 1:
                    raise
                time.sleep(2 ** i)
    ```
  </Tab>
</Tabs>

### Validation Error Handling

Handle validation errors gracefully:

```javascript theme={null}
async function createQuestion(questionData) {
  try {
    const response = await fetch('https://api.prod.qualifi.hr/qsi/gather/questions', {
      method: 'POST',
      headers: {
        'x-api-key': apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(questionData)
    });
    
    if (!response.ok) {
      const error = await response.json();
      
      if (response.status === 400) {
        // Handle validation errors
        console.error('Validation error:', error.error.details);
        // Show user-friendly error messages
        return { error: error.error.message };
      }
      
      throw new Error(error.error.message);
    }
    
    return await response.json();
  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  }
}
```

## Common Error Scenarios

### Invalid Credentials

**Symptom**: 401 Unauthorized

**Solution**:

* Verify credentials are correct
* Check that your API key is correctly formatted and prefixed with `qapi_`
* Ensure using `organizationId:apiKey` (not reversed)

### Resource Not Found

**Symptom**: 404 Not Found

**Solution**:

* Verify resource ID exists
* Check you have access to the resource
* Ensure using correct endpoint path

### Rate Limit Exceeded

**Symptom**: 429 Too Many Requests

**Solution**:

* Implement exponential backoff
* Monitor rate limit headers
* Cache responses when possible
* Reduce request frequency

### Network Errors

**Symptom**: Connection timeout or network errors

**Solution**:

* Implement retry logic
* Use connection pooling
* Set appropriate timeouts
* Handle network failures gracefully

## Best Practices

1. **Always Check Status Codes**: Don't assume requests succeed
2. **Log Errors**: Log errors with request IDs for debugging
3. **User-Friendly Messages**: Translate technical errors to user-friendly messages
4. **Retry Strategically**: Retry transient errors, not client errors
5. **Handle Edge Cases**: Plan for network failures, timeouts, and partial failures
6. **Monitor Error Rates**: Track error rates and types to identify issues

## Related Resources

<CardGroup cols={2}>
  <Card title="Rate Limits" icon="gauge" href="/getting-started/rate-limits">
    Learn about rate limits and throttling
  </Card>

  <Card title="Best Practices" icon="check-circle" href="/guides/best-practices">
    Review API best practices
  </Card>
</CardGroup>
