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

# Error Handling

> Complete reference for HITL.sh API errors, status codes, and troubleshooting guide

# Error Handling

HITL.sh APIs use conventional HTTP status codes and provide detailed error messages to help you debug issues quickly. All errors follow a consistent format for easy parsing and handling.

## Error Response Format

All API errors return a JSON response with the following structure:

```json theme={null}
{
  "error": true,
  "msg": "Human-readable error description",
  "data": {
    // Additional error details (optional)
  }
}
```

### Error Response Fields

<ResponseField name="error" type="boolean">
  Always `true` for error responses
</ResponseField>

<ResponseField name="msg" type="string">
  Human-readable error message describing what went wrong
</ResponseField>

<ResponseField name="data" type="object">
  Additional error context, validation details, or debugging information (optional)
</ResponseField>

## HTTP Status Codes

### 2xx Success

<AccordionGroup>
  <Accordion title="200 OK">
    Request succeeded. Response contains the requested data.

    ```json theme={null}
    {
      "error": false,
      "msg": "Operation completed successfully",
      "data": { /* response data */ }
    }
    ```
  </Accordion>

  <Accordion title="201 Created">
    Resource was created successfully.

    ```json theme={null}
    {
      "error": false,
      "msg": "Loop created successfully",
      "data": { /* created resource */ }
    }
    ```
  </Accordion>
</AccordionGroup>

### 4xx Client Errors

<AccordionGroup>
  <Accordion title="400 Bad Request">
    Request data is invalid or malformed.

    **Common causes:**

    * Missing required fields
    * Invalid field values
    * Malformed JSON
    * Validation failures

    **Invalid request body:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Invalid request body"
    }
    ```

    **Invalid ID format:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Invalid loop ID format"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Invalid request ID format"
    }
    ```

    **Missing required fields:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Loop name is required"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Loop icon is required"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Request text is required"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "timeout_seconds is required for time-sensitive requests"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Image URL is required when type is image"
    }
    ```

    **Invalid configuration:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Invalid response configuration",
      "data": "options array required for select response type"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Invalid default response",
      "data": "default_response must match one of the configured options"
    }
    ```

    **State validation errors:**

    ```json theme={null}
    {
      "error": true,
      "msg": "No active members found in the loop"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Request cannot be cancelled in current state"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Feedback can only be added to completed requests"
    }
    ```
  </Accordion>

  <Accordion title="401 Unauthorized">
    Authentication is missing or invalid.

    **Common causes:**

    * Missing API key
    * Invalid API key
    * Malformed authorization header
    * Inactive API key

    **Missing Authorization header:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Missing Authorization header"
    }
    ```

    **Invalid header format:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Invalid Authorization header format. Use 'Bearer <api_key>'"
    }
    ```

    **Empty API key:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Empty API key"
    }
    ```

    **Invalid API key:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Invalid API key"
    }
    ```

    **Inactive API key:**

    ```json theme={null}
    {
      "error": true,
      "msg": "API key is inactive"
    }
    ```

    **API key required:**

    ```json theme={null}
    {
      "error": true,
      "msg": "API key required"
    }
    ```
  </Accordion>

  <Accordion title="403 Forbidden">
    Authentication is valid but access is denied.

    **Common causes:**

    * Not the resource owner (loop creator)
    * Not a member of the loop
    * Insufficient permissions for the operation

    **Access denied to loop:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Access denied to this loop"
    }
    ```

    **Access denied to request:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Access denied to this request"
    }
    ```

    **Creator-only operations:**

    Only loop creators can create requests:

    ```json theme={null}
    {
      "error": true,
      "msg": "Only loop creators can create requests"
    }
    ```

    Only loop creator can update:

    ```json theme={null}
    {
      "error": true,
      "msg": "Only loop creator can update the loop"
    }
    ```

    Only loop creator can delete:

    ```json theme={null}
    {
      "error": true,
      "msg": "Only loop creator can delete the loop"
    }
    ```

    Only loop creator can remove members:

    ```json theme={null}
    {
      "error": true,
      "msg": "Only loop creator can remove members"
    }
    ```

    Loop creator cannot remove themselves:

    ```json theme={null}
    {
      "error": true,
      "msg": "Loop creator cannot remove themselves"
    }
    ```
  </Accordion>

  <Accordion title="404 Not Found">
    The requested resource doesn't exist.

    **Common causes:**

    * Invalid resource ID
    * Resource was deleted
    * Typo in endpoint URL
    * Resource doesn't belong to your account

    **Loop not found:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Loop not found"
    }
    ```

    **Request not found:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Request not found"
    }
    ```

    **User is not a member:**

    ```json theme={null}
    {
      "error": true,
      "msg": "User is not a member of this loop"
    }
    ```
  </Accordion>

  <Accordion title="429 Too Many Requests">
    Rate limit has been exceeded. Limits reset at the top of each hour.

    **Rate limit exceeded:**

    ```json theme={null}
    {
      "error": true,
      "msg": "Rate limit exceeded. Maximum 100 requests per hour per API key."
    }
    ```

    **API key usage limit exceeded:**

    ```json theme={null}
    {
      "error": true,
      "msg": "API key usage limit exceeded"
    }
    ```

    **Response headers (included in all responses):**

    ```
    X-RateLimit-Limit: 100
    X-RateLimit-Remaining: 0
    X-RateLimit-Reset: 1704204000
    ```

    The `X-RateLimit-Reset` header contains a Unix timestamp indicating when the rate limit will reset (top of the next hour).
  </Accordion>
</AccordionGroup>

### 5xx Server Errors

<AccordionGroup>
  <Accordion title="500 Internal Server Error">
    An unexpected error occurred on our servers.

    **Common server errors:**

    Database errors:

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to retrieve loops"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to retrieve loop"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to create loop"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to update loop"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to retrieve requests"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to retrieve request"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to cancel request"
    }
    ```

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to add feedback"
    }
    ```

    User information errors:

    ```json theme={null}
    {
      "error": true,
      "msg": "Failed to get user information"
    }
    ```

    **What to do:**

    * Retry the request after a short delay
    * Check our status page at [status.hitl.sh](https://status.hitl.sh)
    * Contact support if the issue persists
  </Accordion>

  <Accordion title="502 Bad Gateway">
    Gateway or proxy error, usually temporary.

    ```json theme={null}
    {
      "error": true,
      "msg": "Service temporarily unavailable"
    }
    ```
  </Accordion>

  <Accordion title="503 Service Unavailable">
    Service is temporarily unavailable, usually due to maintenance.

    ```json theme={null}
    {
      "error": true,
      "msg": "Service temporarily unavailable"
    }
    ```
  </Accordion>
</AccordionGroup>

## Common Error Scenarios

### Validation Errors

**Request Text Too Long:**

```json theme={null}
{
  "error": true,
  "msg": "Validation failed",
  "data": "request_text must be between 1 and 2000 characters"
}
```

**Invalid Response Configuration:**

```json theme={null}
{
  "error": true,
  "msg": "Invalid response configuration",
  "data": "options array required for select response type"
}
```

**Invalid Enum Value:**

```json theme={null}
{
  "error": true,
  "msg": "Validation failed",
  "data": "priority must be one of: low, medium, high, critical"
}
```

### Resource Access Errors

**Loop Not Found:**

```json theme={null}
{
  "error": true,
  "msg": "Loop not found"
}
```

**Request Already Cancelled:**

```json theme={null}
{
  "error": true,
  "msg": "Request cannot be cancelled in current state"
}
```

**No Active Members:**

```json theme={null}
{
  "error": true,
  "msg": "No active members found in the loop"
}
```

### Authentication Errors

**Missing API Key:**

```json theme={null}
{
  "error": true,
  "msg": "API key required"
}
```

**Invalid API Key Format:**

```json theme={null}
{
  "error": true,
  "msg": "Invalid API key format"
}
```

**Expired Session:**

```json theme={null}
{
  "error": true,
  "msg": "Session has expired. Please log in again."
}
```

## Error Handling Best Practices

### 1. Implement Retry Logic

Use exponential backoff for transient errors:

<CodeGroup>
  ```python Python theme={null}
  import time
  import random
  import requests

  def make_request_with_retry(url, headers, data=None, max_retries=3):
      retryable_status_codes = [429, 500, 502, 503, 504]
      
      for attempt in range(max_retries):
          try:
              if data:
                  response = requests.post(url, headers=headers, json=data)
              else:
                  response = requests.get(url, headers=headers)
              
              if response.status_code not in retryable_status_codes:
                  return response
              
              if attempt < max_retries - 1:  # Don't delay on last attempt
                  # Exponential backoff with jitter
                  delay = (2 ** attempt) + random.uniform(0, 1)
                  time.sleep(delay)
                  
          except requests.exceptions.RequestException as e:
              if attempt == max_retries - 1:
                  raise e
              time.sleep(2 ** attempt)
      
      return response
  ```

  ```javascript Node.js theme={null}
  async function makeRequestWithRetry(url, options, maxRetries = 3) {
      const retryableStatusCodes = [429, 500, 502, 503, 504];
      
      for (let attempt = 0; attempt < maxRetries; attempt++) {
          try {
              const response = await fetch(url, options);
              
              if (!retryableStatusCodes.includes(response.status)) {
                  return response;
              }
              
              if (attempt < maxRetries - 1) {
                  // Exponential backoff with jitter
                  const delay = (2 ** attempt) * 1000 + Math.random() * 1000;
                  await new Promise(resolve => setTimeout(resolve, delay));
              }
              
          } catch (error) {
              if (attempt === maxRetries - 1) {
                  throw error;
              }
              await new Promise(resolve => setTimeout(resolve, 2 ** attempt * 1000));
          }
      }
  }
  ```
</CodeGroup>

### 2. Handle Rate Limits Gracefully

<CodeGroup>
  ```python Python theme={null}
  import time
  import requests

  class HITLAPIClient:
      def __init__(self, api_key):
          self.api_key = api_key
          self.base_url = "https://api.hitl.sh/v1"
          
      def make_request(self, method, endpoint, data=None):
          url = f"{self.base_url}{endpoint}"
          headers = {
              "Authorization": f"Bearer {self.api_key}",
              "Content-Type": "application/json"
          }
          
          response = requests.request(method, url, headers=headers, json=data)
          
          if response.status_code == 429:
              # Extract reset time from response
              reset_time = response.headers.get('X-RateLimit-Reset')
              if reset_time:
                  wait_time = int(reset_time) - int(time.time())
                  if wait_time > 0:
                      print(f"Rate limited. Waiting {wait_time} seconds...")
                      time.sleep(wait_time)
                      # Retry the request
                      return self.make_request(method, endpoint, data)
          
          return response
  ```

  ```javascript Node.js theme={null}
  class HITLAPIClient {
      constructor(apiKey) {
          this.apiKey = apiKey;
          this.baseUrl = 'https://api.hitl.sh/v1';
      }
      
      async makeRequest(method, endpoint, data = null) {
          const url = `${this.baseUrl}${endpoint}`;
          const options = {
              method,
              headers: {
                  'Authorization': `Bearer ${this.apiKey}`,
                  'Content-Type': 'application/json'
              }
          };
          
          if (data) {
              options.body = JSON.stringify(data);
          }
          
          const response = await fetch(url, options);
          
          if (response.status === 429) {
              const resetTime = response.headers.get('X-RateLimit-Reset');
              if (resetTime) {
                  const waitTime = parseInt(resetTime) - Math.floor(Date.now() / 1000);
                  if (waitTime > 0) {
                      console.log(`Rate limited. Waiting ${waitTime} seconds...`);
                      await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
                      return this.makeRequest(method, endpoint, data);
                  }
              }
          }
          
          return response;
      }
  }
  ```
</CodeGroup>

### 3. Validate Requests Client-Side

Implement client-side validation to catch errors early:

<CodeGroup>
  ```python Python theme={null}
  def validate_create_request_payload(payload):
      """Validate request payload before sending to API"""
      errors = []
      
      # Required fields
      required_fields = ['processing_type', 'type', 'priority', 'request_text', 
                        'response_type', 'response_config', 'default_response', 'platform']
      
      for field in required_fields:
          if field not in payload or not payload[field]:
              errors.append(f"{field} is required")
      
      # Enum validations
      if 'processing_type' in payload:
          valid_processing_types = ['time-sensitive', 'deferred']
          if payload['processing_type'] not in valid_processing_types:
              errors.append(f"processing_type must be one of: {', '.join(valid_processing_types)}")
      
      if 'priority' in payload:
          valid_priorities = ['low', 'medium', 'high', 'critical']
          if payload['priority'] not in valid_priorities:
              errors.append(f"priority must be one of: {', '.join(valid_priorities)}")
      
      # Custom validations
      if payload.get('processing_type') == 'time-sensitive' and 'timeout_seconds' not in payload:
          errors.append("timeout_seconds is required for time-sensitive requests")
      
      if 'timeout_seconds' in payload:
          timeout = payload['timeout_seconds']
          if not isinstance(timeout, int) or timeout < 60 or timeout > 86400:
              errors.append("timeout_seconds must be between 60 and 86400")
      
      return errors
  ```

  ```javascript Node.js theme={null}
  function validateCreateRequestPayload(payload) {
      const errors = [];
      
      // Required fields
      const requiredFields = ['processing_type', 'type', 'priority', 'request_text', 
                             'response_type', 'response_config', 'default_response', 'platform'];
      
      for (const field of requiredFields) {
          if (!payload[field]) {
              errors.push(`${field} is required`);
          }
      }
      
      // Enum validations
      if (payload.processing_type) {
          const validProcessingTypes = ['time-sensitive', 'deferred'];
          if (!validProcessingTypes.includes(payload.processing_type)) {
              errors.push(`processing_type must be one of: ${validProcessingTypes.join(', ')}`);
          }
      }
      
      if (payload.priority) {
          const validPriorities = ['low', 'medium', 'high', 'critical'];
          if (!validPriorities.includes(payload.priority)) {
              errors.push(`priority must be one of: ${validPriorities.join(', ')}`);
          }
      }
      
      // Custom validations
      if (payload.processing_type === 'time-sensitive' && !payload.timeout_seconds) {
          errors.push('timeout_seconds is required for time-sensitive requests');
      }
      
      if (payload.timeout_seconds) {
          const timeout = payload.timeout_seconds;
          if (!Number.isInteger(timeout) || timeout < 60 || timeout > 86400) {
              errors.push('timeout_seconds must be between 60 and 86400');
          }
      }
      
      return errors;
  }
  ```
</CodeGroup>

### 4. Log Errors for Debugging

Implement comprehensive error logging:

<CodeGroup>
  ```python Python theme={null}
  import logging
  import json

  logger = logging.getLogger(__name__)

  def log_api_error(response, endpoint, payload=None):
      """Log API errors with context for debugging"""
      try:
          error_data = response.json()
      except:
          error_data = {"msg": "Failed to parse error response"}
      
      log_entry = {
          "endpoint": endpoint,
          "status_code": response.status_code,
          "error_message": error_data.get("msg", "Unknown error"),
          "error_data": error_data.get("data"),
          "request_payload": payload,
          "response_headers": dict(response.headers)
      }
      
      logger.error(f"API Error: {json.dumps(log_entry, indent=2)}")
      
      return log_entry

  # Usage
  response = make_api_request(url, payload)
  if response.status_code >= 400:
      log_api_error(response, endpoint, payload)
  ```

  ```javascript Node.js theme={null}
  function logAPIError(response, endpoint, payload = null) {
      const logEntry = {
          endpoint,
          status: response.status,
          statusText: response.statusText,
          requestPayload: payload,
          timestamp: new Date().toISOString()
      };
      
      response.json().then(errorData => {
          logEntry.errorMessage = errorData.msg || 'Unknown error';
          logEntry.errorData = errorData.data;
          
          console.error('API Error:', JSON.stringify(logEntry, null, 2));
          
          // Send to your logging service
          // sendToLoggingService(logEntry);
      }).catch(() => {
          logEntry.errorMessage = 'Failed to parse error response';
          console.error('API Error:', JSON.stringify(logEntry, null, 2));
      });
      
      return logEntry;
  }
  ```
</CodeGroup>

## Debugging Guide

### Common Issues and Solutions

<AccordionGroup>
  <Accordion title="API Key Not Working">
    **Symptoms:** Getting 401 Unauthorized errors

    **Debugging steps:**

    1. Verify API key is correct (no extra spaces)
    2. Check header format: `Authorization: Bearer your_key_here`
    3. Ensure key hasn't been revoked in dashboard
    4. Try generating a new API key

    ```bash theme={null}
    # Test API key
    curl -v -H "Authorization: Bearer your_api_key" https://api.hitl.sh/v1/api/loops
    ```
  </Accordion>

  <Accordion title="Request Validation Failing">
    **Symptoms:** Getting 400 Bad Request with validation errors

    **Debugging steps:**

    1. Check required fields are present
    2. Verify enum values are correct
    3. Validate field types and formats
    4. Check field length constraints

    ```python theme={null}
    # Debug validation
    import json

    payload = {
        "name": "Test Loop",
        "icon": "test"
    }

    print("Payload:", json.dumps(payload, indent=2))

    # Check against API requirements
    required_fields = ["name", "icon"]
    for field in required_fields:
        if field not in payload:
            print(f"Missing required field: {field}")
    ```
  </Accordion>

  <Accordion title="Rate Limit Issues">
    **Symptoms:** Getting 429 Too Many Requests

    **Debugging steps:**

    1. Check rate limit headers in response
    2. Implement exponential backoff
    3. Consider upgrading API tier
    4. Cache responses where possible

    ```bash theme={null}
    # Check rate limit status
    curl -I -H "Authorization: Bearer your_api_key" https://api.hitl.sh/v1/api/loops

    # Look for these headers:
    # X-RateLimit-Limit: 100
    # X-RateLimit-Remaining: 0
    # X-RateLimit-Reset: 1642237200
    ```
  </Accordion>

  <Accordion title="Timeout Errors">
    **Symptoms:** Requests timing out or 504 errors

    **Debugging steps:**

    1. Check our status page: [status.hitl.sh](https://status.hitl.sh)
    2. Increase request timeout in your client
    3. Try the request again after a delay
    4. Contact support if issue persists

    ```python theme={null}
    # Increase timeout
    import requests

    response = requests.get(
        url, 
        headers=headers, 
        timeout=30  # 30 second timeout
    )
    ```
  </Accordion>
</AccordionGroup>

### Request/Response Debugging

Enable verbose logging to see full HTTP requests and responses:

<CodeGroup>
  ```bash cURL theme={null}
  # Use -v flag for verbose output
  curl -v -H "Authorization: Bearer your_api_key" \
       -H "Content-Type: application/json" \
       -d '{"name": "Test Loop", "icon": "test"}' \
       https://api.hitl.sh/v1/api/loops
  ```

  ```python Python theme={null}
  import requests
  import logging

  # Enable debug logging
  logging.basicConfig(level=logging.DEBUG)
  logging.getLogger("requests.packages.urllib3").setLevel(logging.DEBUG)
  logging.getLogger("urllib3.connectionpool").setLevel(logging.DEBUG)

  response = requests.post(url, headers=headers, json=data)
  ```

  ```javascript Node.js theme={null}
  // Use a library like axios-debug-log
  const axios = require('axios');

  // Create axios instance with logging
  const api = axios.create({
      baseURL: 'https://api.hitl.sh/v1',
      headers: {
          'Authorization': 'Bearer your_api_key'
      }
  });

  // Log requests and responses
  api.interceptors.request.use(request => {
      console.log('Request:', request);
      return request;
  });

  api.interceptors.response.use(
      response => {
          console.log('Response:', response);
          return response;
      },
      error => {
          console.log('Error:', error.response);
          return Promise.reject(error);
      }
  );
  ```
</CodeGroup>

## Getting Help

### Self-Service Resources

<CardGroup cols={2}>
  <Card title="API Status" icon="activity" href="https://status.hitl.sh">
    Check if there are any ongoing service issues.
  </Card>

  <Card title="Community Forum" icon="users" href="https://discord.gg/jYVrpmnMP9">
    Ask questions and get help from the community.
  </Card>

  <Card title="Documentation" icon="book" href="/api-reference/introduction">
    Review API documentation and examples.
  </Card>

  <Card title="GitHub Issues" icon="github" href="https://github.com/hitl-sh/feedback">
    Report bugs or request new features.
  </Card>
</CardGroup>

### Contacting Support

When contacting support, please include:

1. **Request ID** (if available from response headers)
2. **Timestamp** of when the error occurred
3. **Full error response** including status code and message
4. **Request details** (endpoint, method, payload)
5. **Your API key ID** (not the actual key)

<Card title="Contact Support" icon="life-ring" href="mailto:support@hitl.sh">
  Email us at [support@hitl.sh](mailto:support@hitl.sh) with your issue details.
</Card>

## Next Steps

<CardGroup cols={2}>
  <Card title="Authentication Guide" icon="key" href="/api-reference/authentication">
    Learn about API keys and security best practices.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/api-reference/webhooks">
    Use callback URLs to receive notifications when requests complete.
  </Card>
</CardGroup>
