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

> ## Agent Instructions
> Agents: start with https://docs.pre.dev/agents.md, which has complete recipes, plan access, polling rules, errors and limits.
> Authenticate with the workspace API key (pdk_…) from Integrations → Built-in, sent as Authorization: Bearer <key>.
> REST API: https://api.pre.dev (OpenAPI: https://docs.pre.dev/api-reference/openapi.json). AI Gateway: https://api.pre.dev/v1, OpenAI-compatible (OpenAPI: https://docs.pre.dev/api-reference/ai-gateway.openapi.json).
> pre.dev MCP server: https://api.pre.dev/mcp. Search these docs over MCP at https://docs.pre.dev/mcp.

# Errors and retries

> Handle HTTP failures, browser task outcomes, AI Gateway error codes, stream errors, and safe retries.

Check the HTTP status before parsing a success response. Successful HTTP delivery and successful task execution are separate: a browser batch can return HTTP `200` with individual task failures, and a specification status request can return HTTP `200` with `status: "failed"`.

## HTTP errors

| HTTP | Meaning | Next step |
| - | - | - |
| `400` | Missing input, invalid ID, or an oversized browser batch | Correct the request |
| `401` | Missing/invalid credentials, or the account cannot authenticate for this interface | Check the key and [account access](/api-reference/authentication) |
| `402` | Insufficient credits or a subscription requirement | Read the message and any `actionUrl` |
| `403` | Access denied or specification trial exhausted | Check account context and plan eligibility |
| `404` | Resource missing or inaccessible | Check the returned ID and the caller |
| `429` | Rate limit or browser in-flight limit reached | Back off; inspect your [queue](/browser-agents/api/queue-status) |
| `500` | Server-side failure | Inspect whether work was accepted before resubmitting |
| `503` | Streaming capacity or website verification unavailable | Inspect `code`; retry DNS verification later, or use async submission for streaming capacity |

General API errors usually include `error` and may include `message`. Browser submission gates use a machine-readable `code`:

```json theme={null}
{
  "error": "The submission would exceed your in-flight task limit.",
  "code": "QUEUE_FULL"
}
```

| Browser code | HTTP | Handling |
| - | - | - |
| `INVALID_TASK` | `400` | Correct the task object, instructions, or output schema |
| `INVALID_URL` | `400` | Provide a full HTTP(S) website URL |
| `MISSING_INSTRUCTION` | `400` | Add instructions or a non-empty output schema |
| `URL_UNREACHABLE` | `400` | Fix the domain; no DNS address was found |
| `URL_CHECK_UNAVAILABLE` | `503` | Retry later; no tasks were started or charged |
| `BATCH_TOO_LARGE` | `400` | Split the batch |
| `SUBSCRIPTION_REQUIRED` | `402` | Follow `actionUrl` to review plans |
| `INSUFFICIENT_CREDITS` | `402` | Follow `actionUrl` to add credits |
| `QUEUE_FULL` | `429` | Wait for tasks to finish or submit fewer tasks |
| `RATE_LIMITED` | `429` | Retry with exponential backoff and jitter |

Input validation errors may include a zero-based `taskIndex` and a `field`. Validation rejects the whole batch before charging or starting work. Invalid tasks and explicit permanent URL/DNS failures are not retried in another sandbox; transient execution failures can still be retried.

These codes belong to Browser Agents. Do not assume an Architect `402` has a browser gate code.

## AI Gateway errors

Errors from `https://api.pre.dev/v1` use the OpenAI error shape with an extra `predev` object, so the OpenAI and Anthropic SDKs raise them as their usual typed exceptions.

```json theme={null}
{
  "error": {
    "message": "This pre.dev workspace has no credits left for AI calls. Top up at https://pre.dev/billing or enable auto-recharge.",
    "type": "insufficient_credits",
    "code": "insufficient_credits",
    "param": null,
    "predev": {
      "credits_remaining": 0,
      "estimated_credits": 1.4,
      "topup_url": "https://pre.dev/billing"
    }
  }
}
```

| Code | HTTP | Cause | `predev` fields | Handling |
| - | - | - | - | - |
| `invalid_request` | `400` | A speech request without `model` and `input`, or with a model that does not produce audio | `available_models` for a wrong model | Fix the request |
| `missing_id` | `400` | `GET /v1/generation` without `id` | | Send the generation id |
| `missing_api_key` | `401` | No `Authorization` or `x-api-key` header | | Send the key; see [authentication](/api-reference/authentication) |
| `invalid_api_key` | `401` | Key unknown, or rotated more than 15 minutes ago | | Copy the current key from **Integrations → Built-in** |
| `insufficient_credits` | `402` | The balance cannot cover the call; nothing was sent to the model | `credits_remaining`, `estimated_credits`, `topup_url` | Add credits or enable auto-recharge |
| `subscription_required` | `402` | A Free workspace used its 5-credit gateway allowance | `credits_remaining`, `trial_credits_used`, `topup_url` | Subscribe |
| `not_found` | `404` | Unknown path, or a file, job, response, or generation that belongs to another workspace, including one a request refers to; nothing ran. On `GET /v1/generation`, also a call that recorded no stats (a failed call, for example) or a streamed call that is still running | | Check the path and id; look up a streamed call after its stream ends |
| `not_ready` | `404` or `502` | `GET /v1/generation` found the call, but its stats are not available yet (`404`) or could not be read (`502`) | | Retry in a few seconds |
| `rate_limit_exceeded` | `429` | More than the per-minute request limit | `retry_after` | Wait `Retry-After` seconds, then retry |
| `too_many_auth_failures` | `429` | Too many failed key attempts from one address | `retry_after` | Check the key, then retry after a minute |
| `internal_error` | `500` | An unexpected gateway error | | Retry, and quote `x-predev-request-id` if it persists |
| `upstream_unavailable` | `502` | The model did not answer | | Retry with backoff; consider `models` fallbacks |
| `catalog_unavailable` | `502` or `503` | The model catalog could not be read: `502` from the catalog listings, which carries no `predev` object, and `503` from `GET /v1/models/public` | | Retry shortly |
| `balance_unavailable` | `503` | The balance check could not complete | `retry_after` | Wait `Retry-After` seconds, then retry |

The error `type` follows the OpenAI convention for the status, for example `authentication_error` for `401` and `rate_limit_error` for `429`; for `402` it repeats the code. A `429` also sets `Retry-After`. [Rate limits](/coding-agent/plans-and-credits#limits) lists the per-minute limits.

```json theme={null}
{
  "error": {
    "message": "The free trial includes 5 credits of AI calls and this workspace has used them. Subscribe at https://pre.dev/billing to keep going.",
    "type": "subscription_required",
    "code": "subscription_required",
    "param": null,
    "predev": {
      "credits_remaining": 18,
      "trial_credits_used": 5,
      "topup_url": "https://pre.dev/billing"
    }
  }
}
```

When the model rejects a request, for example an unknown model id, a malformed request, or an unsupported parameter, the error keeps its HTTP status and its message about the request, in the same OpenAI error shape. Check the model id against [`GET /v1/models`](/ai-gateway/api/models) first.

The OpenAI and Anthropic SDKs raise typed exceptions by status: `AuthenticationError` (401), `RateLimitError` (429), `NotFoundError` (404), and `APIStatusError` with the original `status` for 402, 502, and 503. Read `error.code` from the body to tell `insufficient_credits` from `subscription_required`, and `x-predev-request-id` from the response headers when reporting a problem.

```typescript theme={null}
import OpenAI from 'openai';

try {
  await client.chat.completions.create({ model: 'anthropic/claude-sonnet-5', messages });
} catch (error) {
  if (error instanceof OpenAI.APIError) {
    const code = (error.error as any)?.code;
    if (code === 'insufficient_credits') redirectTo((error.error as any).predev.topup_url);
    else if (error.status === 429) scheduleRetry(Number(error.headers?.get('retry-after') ?? 5));
    else throw error;
  }
}
```

## Streaming failures

Once SSE response headers have been sent, a failure arrives as an `event: error` frame, even though the HTTP status is `200`. The browser SDKs raise an exception for these frames. A disconnected stream or EOF without `done` does not establish success; fetch the run by its saved ID.

The existing-run stream's `done` payload contains only the batch status. Fetch the final result after it. The submission stream's `done` payload contains the full batch. See [streaming](/browser-agents/api/stream-task).

AI Gateway streams that fail after headers are sent end early; the charge covers what the model generated. See [gateway streaming](/ai-gateway/streaming).

## Retry submissions

For REST browser requests, send a stable **`Idempotency-Key`** header. If a run with the same caller/key already exists from the last 24 hours, the API returns that run as JSON instead of creating a new one, even if the retry requested streaming. Keep the payload the same and use a new key for intentional new work. The API does not compare payloads for you.

Do not rely on this lookup as a lock for simultaneous duplicate requests. Serialize retries of the same logical submission.

Specification generation has no documented idempotency key. If a request times out, check history before generating again. A retry can create another specification and consume more credits.

## SDK exceptions

Both `predev-api` SDKs provide `AuthenticationError`, `RateLimitError`, and `PredevAPIError`. Browser gate codes also map to `SubscriptionRequiredError`, `InsufficientCreditsError`, `QueueFullError`, and `BatchTooLargeError`. Billing exceptions may include `actionUrl` in Node or `action_url` in Python.

The Node base exception exposes `message`; Python exceptions can be read with `str(error)`. Neither SDK exposes a `statusCode` / `status_code` property on its base exception. Use direct HTTP when your application needs the original status, headers, and full response body.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.