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

# Error Handling

> Understanding API errors and how to handle them

# Error Handling

The VibePeak API uses standard HTTP status codes and returns detailed error information to help you diagnose and resolve issues.

## Error Response Format

All errors follow a consistent structure:

```json theme={null}
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error description",
    "request_id": "req_xyz123",
    "details": {
      // Additional context (optional)
    }
  }
}
```

| Field        | Description                                           |
| ------------ | ----------------------------------------------------- |
| `code`       | Machine-readable error code for programmatic handling |
| `message`    | Human-readable description of the error               |
| `request_id` | Unique identifier for support reference               |
| `details`    | Additional context about the error (when available)   |

## HTTP Status Codes

| Status Code | Description                                  |
| ----------- | -------------------------------------------- |
| `200`       | Success                                      |
| `202`       | Accepted - Task created successfully         |
| `400`       | Bad Request - Invalid parameters             |
| `401`       | Unauthorized - Invalid or missing API key    |
| `403`       | Forbidden - Plan doesn't include API access  |
| `404`       | Not Found - Resource doesn't exist           |
| `429`       | Too Many Requests - Rate limit exceeded      |
| `500`       | Internal Server Error - Something went wrong |

## Error Codes Reference

### Authentication Errors

<AccordionGroup>
  <Accordion title="INVALID_API_KEY" icon="key">
    **Status:** 401 Unauthorized

    The provided API key is invalid or doesn't exist.

    ```json theme={null}
    {
      "error": {
        "code": "INVALID_API_KEY",
        "message": "The provided API key is invalid.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Check that your API key is correct and properly formatted (`vpk_live_xxxxx` or `vpk_test_xxxxx`).
  </Accordion>

  <Accordion title="MISSING_API_KEY" icon="key">
    **Status:** 401 Unauthorized

    No API key was provided in the request.

    ```json theme={null}
    {
      "error": {
        "code": "MISSING_API_KEY",
        "message": "API key is required. Include it in the Authorization header.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Add the `Authorization: Bearer vpk_live_xxxxx` header to your request.
  </Accordion>
</AccordionGroup>

### Authorization Errors

<AccordionGroup>
  <Accordion title="PLAN_NOT_ALLOWED" icon="crown">
    **Status:** 403 Forbidden

    Your subscription plan doesn't include API access. Only Plus, Pro, Max, and Enterprise plans have API access.

    ```json theme={null}
    {
      "error": {
        "code": "PLAN_NOT_ALLOWED",
        "message": "Your plan does not include API access. Please upgrade to Plus, Pro or Max.",
        "request_id": "req_xyz123",
        "details": {
          "current_plan": "none",
          "required_credits": 10,
          "current_credits": 0
        }
      }
    }
    ```

    **Solution:** [Upgrade your plan](https://vibepeak.ai/pricing) to Plus, Pro, Max, or Enterprise.
  </Accordion>

  <Accordion title="INSUFFICIENT_CREDITS" icon="coins">
    **Status:** 403 Forbidden

    Your account doesn't have enough credits for this operation.

    ```json theme={null}
    {
      "error": {
        "code": "INSUFFICIENT_CREDITS",
        "message": "Insufficient credits. This operation requires 10 credits.",
        "request_id": "req_xyz123",
        "details": {
          "required_credits": 10,
          "current_credits": 5,
          "current_plan": "Plus"
        }
      }
    }
    ```

    **Solution:** [Purchase more credits](https://app.vibepeak.ai/billing) or wait for your monthly credit refresh.
  </Accordion>

  <Accordion title="AVATAR_ACCESS_DENIED" icon="user-slash">
    **Status:** 403 Forbidden

    You don't have permission to use this avatar.

    ```json theme={null}
    {
      "error": {
        "code": "AVATAR_ACCESS_DENIED",
        "message": "You do not have access to this avatar.",
        "request_id": "req_xyz123",
        "details": {
          "avatar_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
        }
      }
    }
    ```

    **Solution:** Use a public avatar or one of your custom avatars. Custom avatars can only be accessed by their owner.
  </Accordion>

  <Accordion title="VOICE_ACCESS_DENIED" icon="microphone-slash">
    **Status:** 403 Forbidden

    You don't have permission to use this voice.

    ```json theme={null}
    {
      "error": {
        "code": "VOICE_ACCESS_DENIED",
        "message": "You do not have access to this voice.",
        "request_id": "req_xyz123",
        "details": {
          "voice_id": "cloned-voice-123"
        }
      }
    }
    ```

    **Solution:** Use a public voice or one of your cloned voices. Cloned voices can only be accessed by their owner.
  </Accordion>

  <Accordion title="VOICE_EXPIRED" icon="clock">
    **Status:** 403 Forbidden

    The cloned voice has expired.

    ```json theme={null}
    {
      "error": {
        "code": "VOICE_EXPIRED",
        "message": "This voice has expired.",
        "request_id": "req_xyz123",
        "details": {
          "voice_id": "expired-voice-123"
        }
      }
    }
    ```

    **Solution:** Create a new cloned voice or use a public voice.
  </Accordion>
</AccordionGroup>

### Internal Service Errors

<AccordionGroup>
  <Accordion title="AVATAR_URL_ERROR" icon="image">
    **Status:** 500 Internal Server Error

    Failed to generate a secure URL for the avatar image.

    ```json theme={null}
    {
      "error": {
        "code": "AVATAR_URL_ERROR",
        "message": "Failed to generate secure avatar URL",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** This is a server-side issue. Retry your request. If the issue persists, contact support with the request\_id.
  </Accordion>
</AccordionGroup>

### Rate Limiting Errors

<AccordionGroup>
  <Accordion title="CONCURRENCY_LIMIT_EXCEEDED" icon="gauge">
    **Status:** 429 Too Many Requests

    You've reached your concurrent task limit.

    ```json theme={null}
    {
      "error": {
        "code": "CONCURRENCY_LIMIT_EXCEEDED",
        "message": "You have reached your concurrent task limit of 1. Please wait for existing tasks to complete.",
        "request_id": "req_xyz123",
        "details": {
          "limit": 1,
          "in_flight": 1,
          "plan": "Plus"
        }
      }
    }
    ```

    **Solution:** Wait for existing tasks to complete, or [upgrade your plan](/concepts/rate-limits) for higher limits.
  </Accordion>
</AccordionGroup>

### Validation Errors

<AccordionGroup>
  <Accordion title="INVALID_JSON" icon="code">
    **Status:** 400 Bad Request

    The request body contains invalid JSON that cannot be parsed.

    ```json theme={null}
    {
      "error": {
        "code": "INVALID_JSON",
        "message": "Request body contains invalid JSON. Please check your JSON syntax.",
        "request_id": "req_xyz123",
        "details": {
          "hint": "Ensure your request body is valid JSON with proper quotes, brackets, and commas."
        }
      }
    }
    ```

    **Solution:** Validate your JSON before sending. Common issues include:

    * Missing or extra commas
    * Unquoted property names
    * Single quotes instead of double quotes
    * Trailing commas in arrays or objects
    * Unescaped special characters in strings
  </Accordion>

  <Accordion title="VALIDATION_ERROR" icon="triangle-exclamation">
    **Status:** 400 Bad Request

    The request parameters are invalid.

    ```json theme={null}
    {
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "images must contain between 5 and 9 URLs",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Review the error message and fix the invalid parameters. This also covers invalid enum values such as an unsupported `orientation`.
  </Accordion>

  <Accordion title="INVALID_JSON" icon="code">
    **Status:** 400 Bad Request

    The request body could not be parsed as JSON (e.g. a trailing comma, an unquoted key, or a truncated payload). This is checked before parameter validation, so you'll see it instead of `VALIDATION_ERROR` when the body itself is malformed.

    ```json theme={null}
    {
      "error": {
        "code": "INVALID_JSON",
        "message": "Request body is not valid JSON",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Verify the request body is valid JSON and that the `Content-Type: application/json` header is set. Serialize the body with your language's JSON encoder rather than building it by hand.
  </Accordion>

  <Accordion title="INVALID_AVATAR_ID" icon="user">
    **Status:** 400 Bad Request

    The avatar ID format is invalid.

    ```json theme={null}
    {
      "error": {
        "code": "INVALID_AVATAR_ID",
        "message": "Invalid avatar ID format.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Ensure the avatar ID is a valid UUID format (e.g., `a1b2c3d4-e5f6-7890-abcd-ef1234567890`).
  </Accordion>

  <Accordion title="INVALID_VOICE_ID" icon="microphone">
    **Status:** 400 Bad Request

    The voice ID format is invalid.

    ```json theme={null}
    {
      "error": {
        "code": "INVALID_VOICE_ID",
        "message": "Invalid voice ID format.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Use a valid voice ID from the [List Voices](/api-reference/voices/list-voices) endpoint or a cloned voice ID.
  </Accordion>

  <Accordion title="IMAGE_INACCESSIBLE" icon="image">
    **Status:** 400 Bad Request

    One or more image URLs are not accessible.

    ```json theme={null}
    {
      "error": {
        "code": "IMAGE_INACCESSIBLE",
        "message": "One or more images are not accessible.",
        "request_id": "req_xyz123",
        "details": {
          "invalid_images": ["https://example.com/missing.jpg"]
        }
      }
    }
    ```

    **Solution:** Ensure all image URLs are publicly accessible HTTPS URLs.
  </Accordion>

  <Accordion title="IMAGE_TIMEOUT" icon="clock">
    **Status:** 400 Bad Request

    Image validation timed out.

    ```json theme={null}
    {
      "error": {
        "code": "IMAGE_TIMEOUT",
        "message": "Image validation timed out. Please ensure all images are publicly accessible.",
        "request_id": "req_xyz123",
        "details": {
          "invalid_images": ["https://slow-server.com/image.jpg"]
        }
      }
    }
    ```

    **Solution:** Use images hosted on fast, reliable servers.
  </Accordion>

  <Note>
    Narrated slideshow requests no longer return `MIXED_ORIENTATIONS`. Use the optional `orientation` field to request `portrait` or `landscape` output explicitly, or omit it and let the API auto-detect from the first image.
  </Note>

  <Accordion title="SSRF_BLOCKED" icon="shield">
    **Status:** 400 Bad Request

    Image URL points to a private network.

    ```json theme={null}
    {
      "error": {
        "code": "SSRF_BLOCKED",
        "message": "Image URL points to a private network which is not allowed.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Use publicly accessible image URLs. Private/internal network URLs (localhost, 192.168.x.x, etc.) are not allowed.
  </Accordion>
</AccordionGroup>

### Script Length Errors

The `script` field must fit a **per-scene budget** that scales with the number of images. Each image becomes a scene of roughly 3 seconds, so the script needs **65–85 characters per image** to produce a video where the narration neither cuts off early nor leaves silence at the end.

| Images | Min characters | Max characters |
| ------ | -------------- | -------------- |
| 1      | 65             | 85             |
| 3      | 195            | 255            |
| 5      | 325            | 425            |
| 9      | 585            | 765            |

<AccordionGroup>
  <Accordion title="SCRIPT_TOO_SHORT" icon="text-size">
    **Status:** 400 Bad Request

    The script is shorter than `image_count × 65` characters. The narration would end before the video does, leaving silent frames.

    ```json theme={null}
    {
      "error": {
        "code": "SCRIPT_TOO_SHORT",
        "message": "Script is too short for 3 image(s). Minimum 195 characters required (65 per scene), but got 134. Either lengthen the script or send fewer images.",
        "request_id": "req_xyz123",
        "details": {
          "script_length": 134,
          "min_length": 195,
          "max_length": 255,
          "image_count": 3,
          "chars_per_scene_min": 65,
          "chars_per_scene_max": 85
        }
      }
    }
    ```

    **Solution:** Either expand the script up to at least `min_length` characters, or remove images until `image_count × 65` ≤ your script length.
  </Accordion>

  <Accordion title="SCRIPT_TOO_LONG" icon="text-size">
    **Status:** 400 Bad Request

    The script is longer than `image_count × 85` characters. The narration would be rushed to fit within the video, harming TTS quality.

    ```json theme={null}
    {
      "error": {
        "code": "SCRIPT_TOO_LONG",
        "message": "Script is too long for 3 image(s). Maximum 255 characters allowed (85 per scene), but got 400. Either shorten the script or send more images.",
        "request_id": "req_xyz123",
        "details": {
          "script_length": 400,
          "min_length": 195,
          "max_length": 255,
          "image_count": 3,
          "chars_per_scene_min": 65,
          "chars_per_scene_max": 85
        }
      }
    }
    ```

    **Solution:** Either trim the script down to at most `max_length` characters, or add more images until `image_count × 85` ≥ your script length.
  </Accordion>

  <Accordion title="SCRIPT_INVALID_CHARACTERS" icon="ban">
    **Status:** 400 Bad Request

    The script contains characters that the TTS engine cannot process. Numbers and symbols are allowed — text-to-speech reads them correctly. Only emojis and other non-speech characters (pictographs, control/zero-width characters) are rejected.

    ```json theme={null}
    {
      "error": {
        "code": "SCRIPT_INVALID_CHARACTERS",
        "message": "Script contains characters not supported by text-to-speech: \"🏠\".",
        "request_id": "req_xyz123",
        "details": {
          "invalid_characters": ["🏠"]
        }
      }
    }
    ```

    **Solution:** Remove any emojis or other non-speech characters from the script.
  </Accordion>
</AccordionGroup>

### Not Found Errors

<AccordionGroup>
  <Accordion title="USER_NOT_FOUND" icon="user-slash">
    **Status:** 404 Not Found

    The user account was not found.

    ```json theme={null}
    {
      "error": {
        "code": "USER_NOT_FOUND",
        "message": "User account not found.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Ensure your API key is associated with a valid user account.
  </Accordion>

  <Accordion title="AVATAR_NOT_FOUND" icon="user">
    **Status:** 404 Not Found

    The specified avatar was not found.

    ```json theme={null}
    {
      "error": {
        "code": "AVATAR_NOT_FOUND",
        "message": "Avatar not found.",
        "request_id": "req_xyz123",
        "details": {
          "avatar_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
        }
      }
    }
    ```

    **Solution:** Use a valid avatar ID from the public avatars list or your custom avatars.
  </Accordion>

  <Accordion title="VOICE_NOT_FOUND" icon="microphone">
    **Status:** 404 Not Found

    The specified voice was not found.

    ```json theme={null}
    {
      "error": {
        "code": "VOICE_NOT_FOUND",
        "message": "Voice not found.",
        "request_id": "req_xyz123",
        "details": {
          "voice_id": "invalid-voice-123"
        }
      }
    }
    ```

    **Solution:** Use a valid voice ID from the [List Voices](/api-reference/voices/list-voices) endpoint or a cloned voice ID.
  </Accordion>

  <Accordion title="TASK_NOT_FOUND" icon="magnifying-glass">
    **Status:** 404 Not Found

    The requested task doesn't exist.

    ```json theme={null}
    {
      "error": {
        "code": "TASK_NOT_FOUND",
        "message": "Task not found.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Verify the task ID is correct.
  </Accordion>
</AccordionGroup>

### Task Errors

<AccordionGroup>
  <Accordion title="IMAGE_PROCESSING_FAILED" icon="image">
    **Status:** Returned in task status (not HTTP error)

    One or more images couldn't be processed.

    ```json theme={null}
    {
      "error": {
        "code": "IMAGE_PROCESSING_FAILED",
        "message": "Failed to process image at index 2: Invalid image format"
      }
    }
    ```

    **Solution:** Ensure all images are accessible URLs with supported formats (JPEG, PNG, WebP).
  </Accordion>

  <Accordion title="TEST_MODE_SIMULATED_FAILURE" icon="flask">
    **Status:** Returned in task status (not HTTP error). Sandbox only.

    A deliberately-failed sandbox task, returned when a request from a `vpk_test_` key includes `"test_scenario": "fail"`. It lets you exercise your error-handling code without spending credits. The same `livemode: false` field that appears on every sandbox response is also set on the task status.

    ```json theme={null}
    {
      "task_id": "task_abc123xyz",
      "status": "failed",
      "livemode": false,
      "error": {
        "code": "TEST_MODE_SIMULATED_FAILURE",
        "message": "Simulated failure for test mode. No video was generated and no credits were used."
      }
    }
    ```

    **Solution:** This is the *expected* response for the `fail` test scenario — not a real failure. Treat it as a hand-rolled fixture for your error-handling path. **Do not retry**: the same `test_scenario` will keep returning the same error. See [Test Mode → The `test_scenario` parameter](/concepts/test-mode#the-test_scenario-parameter) for the other scenarios.
  </Accordion>

  <Accordion title="INVALID_IMAGE_URL" icon="link-slash">
    **Status:** 400 Bad Request

    One or more image URLs are inaccessible, invalid, or point to private networks.

    ```json theme={null}
    {
      "error": {
        "code": "INVALID_IMAGE_URL",
        "message": "Image validation failed",
        "request_id": "req_xyz123",
        "details": {
          "invalid_images": [
            { "index": 2, "url": "https://...", "reason": "Image is not accessible" }
          ]
        }
      }
    }
    ```

    **Solution:** Verify all image URLs are publicly accessible HTTPS URLs.
  </Accordion>

  <Accordion title="INVALID_WATERMARK_URL" icon="link-slash">
    **Status:** 400 Bad Request

    The `elements_config.watermark.url` is inaccessible or does not return an
    image. This is validated up front so a broken logo URL fails immediately
    instead of after the video has rendered. A common cause is a storage URL
    whose object has been deleted or moved — it returns `application/json`
    ("Object not found") rather than the image.

    ```json theme={null}
    {
      "error": {
        "code": "INVALID_WATERMARK_URL",
        "message": "Watermark image not accessible: HTTP 400",
        "request_id": "req_xyz123",
        "details": {
          "watermark_url": "https://example.com/logo.png"
        }
      }
    }
    ```

    **Solution:** Confirm the watermark URL is a publicly accessible HTTPS URL that returns an `image/*` content type (PNG, JPEG, WebP, SVG, or ICO).
  </Accordion>

  <Accordion title="IMAGE_RESOLUTION_TOO_LOW" icon="image">
    **Status:** 400 Bad Request

    One or more source images are below the minimum resolution. VibePeak requires an **HD floor** on every source image: the long side must be at least **1280 px** and the short side at least **720 px**. Anything smaller produces visibly upscaled or blurry output.

    ```json theme={null}
    {
      "error": {
        "code": "IMAGE_RESOLUTION_TOO_LOW",
        "message": "1 image(s) below the minimum resolution. Required: long side ≥ 1280px and short side ≥ 720px.",
        "request_id": "req_xyz123",
        "details": {
          "invalid_images": ["https://example.com/thumbnail.jpg"]
        }
      }
    }
    ```

    **Solution:** Re-upload the offending images at HD or higher. If your source (e.g. a CRM export) only exposes thumbnails, check whether the full-resolution variant is available at a different URL.
  </Accordion>
</AccordionGroup>

### Service Errors

<AccordionGroup>
  <Accordion title="SERVICE_UNAVAILABLE" icon="server">
    **Status:** 503 Service Unavailable

    The video generation service is temporarily unavailable.

    ```json theme={null}
    {
      "error": {
        "code": "SERVICE_UNAVAILABLE",
        "message": "Video generation service is temporarily unavailable. Please try again.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Wait a few minutes and retry your request. Check [status.vibepeak.ai](https://vibepeak.statuspage.io/) for service updates.
  </Accordion>

  <Accordion title="SERVICE_TIMEOUT" icon="clock">
    **Status:** 504 Gateway Timeout

    The service request timed out.

    ```json theme={null}
    {
      "error": {
        "code": "SERVICE_TIMEOUT",
        "message": "Video generation service is taking too long to respond. Please try again.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Retry your request. If the issue persists, contact support.
  </Accordion>

  <Accordion title="SERVICE_ERROR" icon="triangle-exclamation">
    **Status:** 503 Service Unavailable

    An internal service error occurred.

    ```json theme={null}
    {
      "error": {
        "code": "SERVICE_ERROR",
        "message": "Failed to connect to video generation service",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Retry your request. If the issue persists, contact support with the request\_id.
  </Accordion>

  <Accordion title="TTS_ERROR" icon="microphone">
    **Status:** 503 Service Unavailable

    Text-to-speech generation failed.

    ```json theme={null}
    {
      "error": {
        "code": "TTS_ERROR",
        "message": "Text-to-speech service is temporarily unavailable",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Retry your request. The TTS service uses a circuit breaker that may temporarily block requests after repeated failures.
  </Accordion>

  <Accordion title="QUEUE_ERROR" icon="list">
    **Status:** 503 Service Unavailable

    Failed to queue the video generation job.

    ```json theme={null}
    {
      "error": {
        "code": "QUEUE_ERROR",
        "message": "Video generation service is temporarily unavailable. Please try again.",
        "request_id": "req_xyz123"
      }
    }
    ```

    **Solution:** Retry your request after a few seconds.
  </Accordion>
</AccordionGroup>

## Handling Errors

<CodeGroup>
  ```javascript Node.js theme={null}
  async function createSlideshow(images, apiKey) {
    const response = await fetch('https://api.vibepeak.ai/v1/real-estate/narrated-slideshow', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ images })
    });

    const data = await response.json();

    if (!response.ok) {
      const { code, message, request_id, details } = data.error;

      switch (code) {
        case 'INVALID_API_KEY':
        case 'MISSING_API_KEY':
          throw new Error('Authentication failed. Check your API key.');

        case 'PLAN_NOT_ALLOWED':
          throw new Error(`Upgrade required. Current plan: ${details.current_plan}`);

        case 'INSUFFICIENT_CREDITS':
          throw new Error(`Not enough credits. Have ${details.current_credits}, need ${details.required_credits}`);

        case 'AVATAR_NOT_FOUND':
        case 'AVATAR_ACCESS_DENIED':
          throw new Error(`Avatar error: ${message}`);

        case 'VOICE_NOT_FOUND':
        case 'VOICE_ACCESS_DENIED':
        case 'VOICE_EXPIRED':
          throw new Error(`Voice error: ${message}`);

        case 'CONCURRENCY_LIMIT_EXCEEDED':
          throw new Error(`Rate limited. ${details.in_flight}/${details.limit} tasks in progress.`);

        case 'INVALID_JSON':
          throw new Error(`Malformed JSON: ${message}. ${details.hint || ''}`);

        case 'VALIDATION_ERROR':
        case 'IMAGE_INACCESSIBLE':
        case 'IMAGE_TIMEOUT':
          throw new Error(`Invalid request: ${message}`);

        default:
          throw new Error(`API error (${code}): ${message}. Request ID: ${request_id}`);
      }
    }

    return data;
  }
  ```

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

  def create_slideshow(images, api_key):
      response = requests.post(
          'https://api.vibepeak.ai/v1/real-estate/narrated-slideshow',
          headers={
              'Authorization': f'Bearer {api_key}',
              'Content-Type': 'application/json'
          },
          json={'images': images}
      )

      data = response.json()

      if not response.ok:
          error = data['error']
          code = error['code']
          message = error['message']
          request_id = error['request_id']
          details = error.get('details', {})

          if code in ['INVALID_API_KEY', 'MISSING_API_KEY']:
              raise Exception('Authentication failed. Check your API key.')

          if code == 'PLAN_NOT_ALLOWED':
              raise Exception(f"Upgrade required. Current plan: {details.get('current_plan')}")

          if code == 'INSUFFICIENT_CREDITS':
              raise Exception(f"Not enough credits. Have {details.get('current_credits')}, need {details.get('required_credits')}")

          if code in ['AVATAR_NOT_FOUND', 'AVATAR_ACCESS_DENIED']:
              raise Exception(f"Avatar error: {message}")

          if code in ['VOICE_NOT_FOUND', 'VOICE_ACCESS_DENIED', 'VOICE_EXPIRED']:
              raise Exception(f"Voice error: {message}")

          if code == 'CONCURRENCY_LIMIT_EXCEEDED':
              raise Exception(f"Rate limited. {details['in_flight']}/{details['limit']} tasks in progress.")

          if code == 'INVALID_JSON':
              hint = details.get('hint', '')
              raise Exception(f"Malformed JSON: {message}. {hint}")

          if code in ['VALIDATION_ERROR', 'IMAGE_INACCESSIBLE', 'IMAGE_TIMEOUT']:
              raise Exception(f"Invalid request: {message}")

          raise Exception(f"API error ({code}): {message}. Request ID: {request_id}")

      return data
  ```
</CodeGroup>

## Retry Strategy

For transient errors, implement exponential backoff:

```javascript theme={null}
async function withRetry(fn, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      // Don't retry authentication, authorization, or validation errors
      const nonRetryableCodes = [
        'INVALID_API_KEY',
        'MISSING_API_KEY',
        'PLAN_NOT_ALLOWED',
        'INSUFFICIENT_CREDITS',
        'AVATAR_NOT_FOUND',
        'AVATAR_ACCESS_DENIED',
        'VOICE_NOT_FOUND',
        'VOICE_ACCESS_DENIED',
        'VOICE_EXPIRED',
        'INVALID_JSON',
        'VALIDATION_ERROR',
        'IMAGE_INACCESSIBLE',
        'IMAGE_RESOLUTION_TOO_LOW',
        'SCRIPT_TOO_SHORT',
        'SCRIPT_TOO_LONG',
        'SCRIPT_INVALID_CHARACTERS',
        'SSRF_BLOCKED',
        'TEST_MODE_SIMULATED_FAILURE'
      ];
      if (nonRetryableCodes.includes(error.code)) {
        throw error;
      }

      // Retry rate limits and server errors
      if (attempt < maxRetries - 1) {
        const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      throw error;
    }
  }
}
```

<Warning>
  Never retry authentication (`401`) or validation (`400`) errors - they won't succeed on retry.
</Warning>

## Getting Support

When contacting support, include:

1. **Request ID** - Found in every error response
2. **Error code** - The machine-readable error code
3. **Timestamp** - When the error occurred
4. **Request details** - The endpoint and parameters used

Email: [api-support@vibepeak.ai](mailto:api-support@vibepeak.ai)
