> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs-beta-7agmae.voicedub.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Comprehensive guide to handling errors, timeouts, and edge cases in the VoiceDub API

Learn how to properly handle errors, implement retry logic, and troubleshoot common issues when using the VoiceDub API.

## Error Response Format

All API errors return a consistent JSON structure:

**Error Response:**

```json theme={null}
{
  "code": "error_code_here",
  "message": "Human-readable error description"
}
```

## HTTP Status Codes

### 400 Bad Request

Invalid request parameters or malformed data.

**400 Examples:**

```json theme={null}
{
  "code": "invalid_arguments",
  "message": "Invalid request parameters or body",
  "errors": {
    "params": "...",
    "query": "...",
    "body": "..."
  }
}

{
  "code": "voice_not_found",
  "message": "Voice not found or not accessible"
}
```

**Common causes:**

* Invalid UUID format for voice or dub IDs
* Missing required parameters
* Invalid parameter values (e.g., pitch shift outside -24 to +24 range)
* Passing a `voiceId` for a voice that does not exist or is not accessible

### 401 Unauthorized

Authentication failed or API key issues.

**401 Examples:**

```json theme={null}
{
  "code": "unauthorized",
  "message": "You are not authorized to perform this action"
}
```

**Common causes:**

* Missing `Authorization` header
* Incorrect API key format (should be `Api-Key YOUR_KEY`)
* Deleted or expired API key

### 403 Forbidden

Valid request but insufficient permissions or credits.

**403 Examples:**

```json theme={null}
{
  "code": "not_enough_credits",
  "message": "Looks like you don't have enough credits! Purchase more at https://voicedub.ai/developer/billing"
}
```

**Common causes:**

* Insufficient API credits for operation

### 404 Not Found

Resource doesn't exist or you don't have access.

**404 Examples:**

```json theme={null}
{
  "code": "not_found",
  "message": "Dub not found"
}

{
  "code": "not_found", 
  "message": "Voice not found"
}
```

**Common causes:**

* Invalid resource ID

### 429 Rate Limited

Too many requests in a short time period.

**429 Example:**

```json theme={null}
{
  "code": "rate_limit_exceeded",
  "message": "Rate limit exceeded. Please wait before making more requests."
}
```

### 500 Internal Server Error

Server-side error occurred.

**500 Example:**

```json theme={null}
{
  "code": "internal_error",
  "message": "An internal server error occurred. Please try again later."
}
```

**When this happens:**

* Temporary server issues
* Unexpected system errors

## Retry Logic

Implement exponential backoff for transient errors:

<CodeGroup>
  ```javascript Node.js theme={null}
  async function apiRequestWithRetry(url, options, maxRetries = 3) {
    for (let attempt = 0; attempt <= maxRetries; attempt++) {
      try {
        const response = await fetch(url, options);
        
        // Don't retry client errors (4xx except 429)
        if (response.status >= 400 && response.status < 500 && response.status !== 429) {
          const error = await response.json();
          throw new Error(`${error.code}: ${error.message}`);
        }
        
        // Retry server errors (5xx) and rate limits (429)
        if (response.status >= 500 || response.status === 429) {
          if (attempt === maxRetries) {
            throw new Error(`Request failed after ${maxRetries + 1} attempts`);
          }
          
          // Exponential backoff with jitter: 1s-2s, 2s-3s, 4s-5s
          const baseDelay = Math.pow(2, attempt) * 1000;
          const jitter = Math.random() * 1000; // 0-1 second jitter
          const delay = baseDelay + jitter;
          console.log(`Attempt ${attempt + 1} failed, retrying in ${delay.toFixed(0)}ms...`);
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
        
        // Success
        return await response.json();
        
      } catch (error) {
        if (attempt === maxRetries) throw error;
        
        // Exponential backoff with jitter for network errors
        const baseDelay = Math.pow(2, attempt) * 1000;
        const jitter = Math.random() * 1000; // 0-1 second jitter
        const delay = baseDelay + jitter;
        console.log(`Network error, retrying in ${delay.toFixed(0)}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  // Usage
  try {
    const data = await apiRequestWithRetry('https://api.voicedub.ai/v1/me', {
      headers: { 'Authorization': `Api-Key ${apiKey}` }
    });
    console.log('Success:', data);
  } catch (error) {
    console.error('Failed after retries:', error.message);
  }
  ```

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

  def api_request_with_retry(url, headers=None, json=None, max_retries=3):
      for attempt in range(max_retries + 1):
          try:
              if json:
                  response = requests.post(url, headers=headers, json=json)
              else:
                  response = requests.get(url, headers=headers)
              
              # Don't retry client errors (4xx except 429)
              if 400 <= response.status_code < 500 and response.status_code != 429:
                  error_data = response.json()
                  raise Exception(f"{error_data['code']}: {error_data['message']}")
              
              # Retry server errors (5xx) and rate limits (429)
              if response.status_code >= 500 or response.status_code == 429:
                  if attempt == max_retries:
                      raise Exception(f"Request failed after {max_retries + 1} attempts")
                  
                  # Exponential backoff with jitter
                  base_delay = 2 ** attempt
                  jitter = random.uniform(0, 1)
                  delay = base_delay + jitter
                  print(f"Attempt {attempt + 1} failed, retrying in {delay:.1f}s...")
                  time.sleep(delay)
                  continue
              
              # Success
              return response.json()
              
          except requests.exceptions.RequestException as e:
              if attempt == max_retries:
                  raise Exception(f"Network error after {max_retries + 1} attempts: {e}")
              
              base_delay = 2 ** attempt
              jitter = random.uniform(0, 1)
              delay = base_delay + jitter
              print(f"Network error, retrying in {delay:.1f}s...")
              time.sleep(delay)

  # Usage
  try:
      data = api_request_with_retry(
          'https://api.voicedub.ai/v1/me',
          headers={'Authorization': f'Api-Key {api_key}'}
      )
      print('Success:', data)
  except Exception as error:
      print('Failed after retries:', error)
  ```
</CodeGroup>

## Status Polling Best Practices

When polling for job completion, follow these guidelines:

### Polling Intervals

<Warning>
  Never poll faster than once every 3 seconds to avoid rate limiting.
</Warning>

<CodeGroup>
  ```javascript Node.js theme={null}
  async function pollDubStatus(dubId, maxWaitTime = 600000) { // 10 minutes max
    const startTime = Date.now();
    
    while (Date.now() - startTime < maxWaitTime) {
      const response = await fetch(`https://api.voicedub.ai/v1/me/dubs/${dubId}`, {
        headers: { 'Authorization': `Api-Key ${apiKey}` }
      });
      
      if (!response.ok) {
        throw new Error(`Poll failed: ${response.status}`);
      }
      
      const dub = await response.json();
      
      if (dub.status === 'done') {
        return dub; // Success!
      }
      
      if (dub.status === 'error') {
        throw new Error(`Dub failed: ${dub.errorMessage}`);
      }
      
      // Wait 3 seconds before next poll
      await new Promise(resolve => setTimeout(resolve, 3000));
    }
    
    throw new Error('Polling timeout - job did not complete in time');
  }
  ```

  ```python Python theme={null}
  def poll_dub_status(dub_id, max_wait_time=600):  # 10 minutes max
      import time
      start_time = time.time()
      
      while time.time() - start_time < max_wait_time:
          response = requests.get(
              f'https://api.voicedub.ai/v1/me/dubs/{dub_id}',
              headers={'Authorization': f'Api-Key {api_key}'}
          )
          
          if not response.ok:
              raise Exception(f'Poll failed: {response.status_code}')
          
          dub = response.json()
          
          if dub['status'] == 'done':
              return dub  # Success!
          
          if dub['status'] == 'error':
              raise Exception(f'Dub failed: {dub["errorMessage"]}')
          
          # Wait 3 seconds before next poll
          time.sleep(3)
      
      raise Exception('Polling timeout - job did not complete in time')
  ```
</CodeGroup>

## Common Error Scenarios

### Scenario 1: Insufficient Credits

<AccordionGroup>
  <Accordion title="Detection">
    ```json theme={null}
    {
      "code": "not_enough_credits",
      "message": "Looks like you don't have enough credits! Purchase more at https://voicedub.ai/developer/billing"
    }
    ```
  </Accordion>

  <Accordion title="Resolution">
    1. Check current credit balance with `GET /v1/me`
    2. Purchase more credits or enable auto top-up
    3. Retry the request once credits are available
  </Accordion>

  <Accordion title="Prevention">
    * Monitor credit balance regularly
    * Set up auto top-up with appropriate thresholds
    * Check `requiredCredits` after preprocessing before generation
    * Implement credit balance checks in your application
  </Accordion>
</AccordionGroup>

### Scenario 2: Processing Failures

<AccordionGroup>
  <Accordion title="Detection">
    ```json theme={null}
    {
      "status": "error",
      "errorCode": "processing_failed",
      "errorMessage": "Audio processing failed - invalid format or corrupted file"
    }
    ```
  </Accordion>

  <Accordion title="Resolution">
    1. Check audio file format and quality
    2. Try a different audio file or format
    3. Ensure file is not corrupted
    4. Verify file size is under 50MB
    5. Check if audio contains detectable vocals
  </Accordion>

  <Accordion title="Prevention">
    * Use high-quality source audio (192kbps+ MP3 or lossless)
    * Test with shorter clips first
    * Validate file format before upload
    * Use supported formats: MP3, WAV, M4A, FLAC, OGG
  </Accordion>
</AccordionGroup>

### Scenario 3: Rate Limiting

<AccordionGroup>
  <Accordion title="Detection">
    ```json theme={null}
    {
      "code": "rate_limit_exceeded",
      "message": "Rate limit exceeded. Please wait before making more requests."
    }
    ```
  </Accordion>

  <Accordion title="Resolution">
    1. Implement exponential backoff
    2. Wait before retrying (start with 1 second)
    3. Reduce request frequency
  </Accordion>

  <Accordion title="Prevention">
    * Implement request queuing in your application
    * Don't poll faster than once every 3 seconds
    * Cache responses when appropriate
  </Accordion>
</AccordionGroup>

## Error Handling Checklist

<Check>✅ Implement proper HTTP status code handling</Check>
<Check>✅ Parse error responses for specific error codes</Check>
<Check>✅ Implement exponential backoff for retries</Check>
<Check>✅ Set appropriate timeouts for long-running operations</Check>
<Check>✅ Don't retry 4xx errors (except 429)</Check>
<Check>✅ Log errors for debugging and monitoring</Check>
<Check>✅ Provide meaningful error messages to users</Check>
<Check>✅ Monitor credit balance and handle insufficient credits gracefully</Check>

## Debugging Tips

### Enable Request Logging

Log all API requests and responses for debugging:

<CodeGroup>
  ```javascript Node.js theme={null}
  const apiCall = async (url, options) => {
    console.log('API Request:', { url, options });
    
    const response = await fetch(url, options);
    const data = await response.json();
    
    console.log('API Response:', { 
      status: response.status, 
      data 
    });
    
    return { response, data };
  };
  ```

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

  logging.basicConfig(level=logging.DEBUG)

  def api_call(url, **kwargs):
      logging.debug(f'API Request: {url}, {kwargs}')
      
      response = requests.request('GET', url, **kwargs)
      data = response.json() if response.headers.get('content-type', '').startswith('application/json') else None
      
      logging.debug(f'API Response: {response.status_code}, {data}')
      
      return response, data
  ```
</CodeGroup>

### Common Debugging Steps

1. **Verify API key format:** Should be `Api-Key YOUR_API_KEY`
2. **Check request payload:** Ensure JSON is valid and complete
3. **Validate UUIDs:** Voice and dub IDs must be valid UUID format
4. **Test with cURL:** Isolate issues by testing with cURL first
5. **Check network connectivity:** Ensure you can reach `api.voicedub.ai`

### Getting Help

When contacting support, include:

* **Dub/Voice ID**
* **Complete error response** with code and message
* **Steps to reproduce** the issue
* **Audio file details** (format, size, duration)
* **Timestamp** when the error occurred

<Info>
  Need help debugging an issue? Join our [Discord community](https://discord.gg/p7nFCn6EtM) or email [help@voicedub.ai](mailto:help@voicedub.ai) with the details above.
</Info>
