# Errors & limits

Errors are JSON: `{"error": "…"}`, sometimes with extra fields. On the free Community plan, errors caused by its limits (`community_capacity_full`, `daily_quota_exhausted`, `hourly_quota_exhausted`, `threads_exceeded`, `profiles_disabled`, `keep_alive_requires_dedicated`) also carry `"upgrade": {"message": "…", "url": "https://cdpfleet.com/upgrade"}` — what a paid plan changes, linking to the [Community vs paid](https://cdpfleet.com/upgrade) page; the `error` code and HTTP status stay the same. Launch responses:

| Status | `error` | Meaning | What to do |
| --- | --- | --- | --- |
| `400` | `invalid_json` | The body isn't a JSON object. | Fix the request. |
| `400` | `invalid_memory` | `memory` isn't one of the JSON numbers 1, 2, 3 or 4 (it's a multiplier, not megabytes). | Send `"memory": 2` (or 3, 4), or leave it out. |
| `400` | `invalid_channel / invalid_version` | No server in the fleet has that `channel` or `version` (pin). The message lists the channels or majors this browser has. | Pick one from the message; don't retry as is. |
| `400` | `invalid_downloads` | `downloads` isn't `true` or `false`. | Send a JSON boolean. |
| `403` | `downloads_not_available` | `"downloads": true` on a plan that doesn't keep downloads (Community). | Use a paid plan ([Community vs paid](https://cdpfleet.com/upgrade)), or catch the download in code with Playwright's `download.saveAs()`. |
| `400` | `proxy_required` | The launch has no `proxy` and no Community proxy is available for your plan right now (rare). | Add your proxy ([formats](https://cdpfleet.com/docs/proxies)), or your own VPN on a dedicated plan. |
| `400` | `invalid_proxy` | A `cdpfleet-resi` token that doesn't match the grammar, or one used inside a list of proxies. The message names the wrong part. | Fix the token ([residential proxy](https://cdpfleet.com/docs/proxies#residential)). |
| `400` | `tunnel_not_available` | `vpn_tunnel` with a default `proxy` that isn't a `cdpfleet-resi` Tier 1/2 token — or your own proxy, on dedicated plans (or a live swap away from one). `reason` says why. | Use a Tier 1/2 `cdpfleet-resi` token, or launch without `vpn_tunnel` ([VPN Tunnel](https://cdpfleet.com/docs/proxies#vpn-tunnel)). |
| `403` | `vpn_requires_dedicated` | `vpn` (your own VPN) on a plan without dedicated threads. | Use a proxy, or move to a dedicated plan ([Own network](https://cdpfleet.com/docs/proxies#own-network)). |
| `400` | `vpn_not_available` | `vpn` combined with `proxy`/`proxy_rules`, on an unsupported plan, or a live proxy swap on a VPN session. `reason` says which. | Send either `vpn` or a proxy, not both. |
| `400` | `invalid_vpn_config` | The VPN config can't be used: no saved VPN with that name, combined with `vpn_tunnel`, a missing or unsupported field or directive (named in `reason`), a private endpoint, or over 64 KB. | Fix the config, or check the name on Proxies → My VPNs. |
| `400` | `vpn_connect_failed` | Your VPN server didn't answer or refused the credentials, so no request got through it. | Check the server and credentials, then retry. |
| `402` | `proxy_balance_exhausted` | The launch (or a live swap) uses the cdpfleet residential proxy and your balance is used up. | Top up in the dashboard → Proxies. |
| `400` |  | The browser rejected a launch option — an unparseable `proxy`, an unknown Camoufox `config` property or an unsupported `os`. The message says which. | Fix the option; don't retry as is. |
| `401` | `missing_api_key / invalid_api_key` | No key, or an unknown or revoked key. | Check `x-api-key`. |
| `402` | `subscription_inactive` | Your account has no active plan. | Check your plan in the dashboard. |
| `400` | `cdp is not supported on this engine` | `"cdp": true` on a browser without a CDP endpoint. The message lists the supported ones. | Use one of them, or connect to `wsUrl` ([CDP & Puppeteer](https://cdpfleet.com/docs/cdp)). |
| `403` | `keep_alive_requires_dedicated` | `"keep_alive": true` on a shared plan. | Use dedicated threads, or reconnect-free code. |
| `503` | `keep_alive_unavailable` | `keep_alive` isn't switched on for the fleet yet. | Launch without it for now. |
| `400` | `invalid_keep_alive / invalid_record` | `keep_alive` or `record` isn't `true` or `false`. | Send a boolean. |
| `400` | `invalid_profile / profile_unsupported_engine` | `profile` isn't a valid name or `{id, mode}`, or the browser doesn't support profiles yet. | See [Persistent profiles](https://cdpfleet.com/docs/profiles). |
| `403` | `profile_frozen` | The profile is frozen: the account has been over its plan's profile limit for 30 days. | Upgrade to unfreeze it, or delete other profiles ([profiles](https://cdpfleet.com/docs/profiles)). |
| `403` | `profile_limit` | The account already has as many profiles as its plan allows (20 per shared thread, 30 per dedicated thread, at least 100). | Delete one with `DELETE /v1/me/profiles/{name}`, or add threads. |
| `404` | `no_such_profile` | A read-only launch of a profile that doesn't exist yet. | Launch it once in normal mode first. |
| `409` | `profile_in_use` | Another session is writing this profile. | Retry when it ends, or launch with `"mode": "readonly"`. |
| `409` | `profile_engine_mismatch / profile_version_downgrade` | The profile belongs to another browser, or to a newer version of this one. | Use the browser (and channel) it was created with. |
| `503` | `profile_restore_failed / profile_service_unavailable` | The profile couldn't be loaded right now. | Retry. |
| `400` | `invalid_cdp` | `cdp` isn't `true` or `false`. | Send a boolean. |
| `400` | `unsupported_option` | A browser-process field the fleet doesn't take: `args`, `extensions`, `executablePath`, `ignoreDefaultArgs`, `env`, `userDataDir`, `chromiumSandbox`, `devtools`, `downloadsPath` or `tracesDir`. Browsers run with the fleet's own flags. | Remove the field; use the [launch options](https://cdpfleet.com/docs/browsers/chrome) and Playwright (init scripts, routing, headers) instead. |
| `400` | `invalid_start_url` | `start_url` isn't an http(s) URL of at most 2,048 characters. | Fix the URL ([Launch interactive](https://cdpfleet.com/docs/live-view#launch-interactive)). |
| `400` | `start_url_not_viewable / start_url_unsupported` | `start_url` on a session nobody could watch (headless without `live_view`, or headless Firefox, Camoufox or WebKit). | Launch headful, or headless Chromium-based with `"live_view": true`. |
| `400` | `start_url_not_supported` | `start_url` on Rebrowser: its Playwright 1.52 server can't hand the opened page to your code. | Use another Chromium-based browser for Launch interactive. |
| `403` | `profiles_disabled` | A `profile` on the free Community plan. | Upgrade to a paid plan. |
| `503` | `community_capacity_full` | The Community capacity is full right now: Community-plan sessions and launches on the free Community proxy (any plan) share one cap. | Retry after `Retry-After`; on a paid plan, use your own proxy or the residential proxy for launches that must not wait. |
| `403` | `engine_not_allowed` | Your plan doesn't include this browser. | Use another browser or upgrade. |
| `404` | `not_found` | Unknown endpoint, e.g. a misspelled browser. | Check the path. |
| `413` | `payload_too_large` | The launch body is over 100 KB. | Send a smaller body; a long `start_url` or big `config` object is the usual cause. |
| `429` | `rate_limited` | Too many launches per second or minute for your plan. Includes `rps_limit` and `rpm_limit`. | Wait for `Retry-After` seconds. |
| `429` | `threads_exceeded` | This launch would exceed your threads. Includes `threads`, `in_use` and `requested_weight`. | Close a session or wait; `Retry-After: 1`. |
| `429` | `daily_quota_exhausted` | Shared threads: today's pool is used up. Includes the budget and usage. | `Retry-After` counts down to midnight UTC. |
| `429` | `hourly_quota_exhausted` | Shared threads: the last 60 minutes used 25% of your daily pool. Includes the budget and usage. | Wait; the window rolls forward continuously. `Retry-After: 60`. |
| `500` |  | The browser failed to start, e.g. the proxy is unreachable or Camoufox couldn't look up the proxy's location. | Check the proxy, then retry. |
| `503` | `shared_capacity_full` | Shared threads: the shared fleet is full right now. Dedicated threads are never refused for this. | Retry after `Retry-After` (5 s). |
| `503` | `fleet_unavailable / starting_up / route_unavailable` | The fleet is momentarily full. | Retry with backoff. |
| `502` | `route_rejected` | The session couldn't be connected through the fleet's private network, so it was refused rather than exposed. Not billed. | Retry; a new launch goes to another server. |
| `503` | `resi_unavailable` | The cdpfleet residential proxy is momentarily unavailable on the server that took the launch. | Retry; it goes to another server. |
| `503` | `version_unavailable` | The requested `version` exists but no server with it is free right now, or, for a `profile` saved with a newer browser, no server runs at least that version (`min_version`; usually only while a new browser version is rolling out). Includes `available`, the majors you can pick. | Pick one from `available`, or retry the profile launch in a few minutes. |

## Connecting

A WebSocket connect can fail with `401`/`403` (wrong key — only the key that launched the session may connect), `404` (the session has ended, or the 60-second connect window passed), `409` (the session already has a connection) or `502 {"error":"upstream_unreachable"}` (the server running the browser didn't answer — rare). After a `502`, launch a new session rather than reconnecting to the same `wsUrl`; the failed session isn't billed.

## Limits

-   **Threads** — concurrent sessions, weighted by type (see [Sessions & billing](https://cdpfleet.com/docs/sessions)).
-   **Launch rate** — per second and per minute, set by your plan. Only launches that reach the fleet count; refused launches don't.
-   **Daily pool** — shared threads only: threads × browser-minutes per day, resetting at midnight UTC.
-   **Rolling hour** — shared threads only: 25% of the daily pool in any 60 minutes.
-   **Session length** — 24 h at most (15 minutes on the free Community plan); `overall_timeout` is capped at it.
-   **Connect window** — 60 seconds from launch, except sessions launched with `start_url`, which don't need a client.
-   **Open pages per session** — 50 on every plan, counting every tab, popup and context; memory usually runs out first with heavy pages. A page over the cap is closed at once on Chrome, Edge, Brave, Opera, Yandex and Chromium and the session goes on: `newPage()` fails with `page_limit: this session already has 50 pages open (plan limit), so the new page was closed; the session continues`. On the other browsers the session ends with `page_limit`.
-   **Network** — a session reaches only public internet addresses. Loopback, private ranges (10/8, 172.16/12, 192.168/16, CGNAT), link-local and cloud-metadata addresses and the server's own addresses are refused — for pages, redirects, `context.request`, DNS names that resolve to them, and as a `proxy` (a launch naming one gets `400`).
-   **Memory per session** — 2 GB on Community, 4 GB on shared, 6 GB on dedicated (headful sessions get 512 MB more for the display). Going over ends that session with `session_memory_limit`; other sessions aren't affected. Need more? `"memory": 2`–`4` multiplies it, and the session's threads with it.

## Known issues

-   **`net::ERR_NETWORK_CHANGED` on Chromium-based browsers** (since 2026-11): a page load in Chrome, Chromium, Edge, Brave, Opera, Yandex, Whale, Patchright or Rebrowser can be aborted with this error when a VPN or `vpn_tunnel` session starts or ends on the same server — Chromium cancels in-flight navigations whenever the server's network interfaces change. It is rare and short: retry the navigation (`page.goto` again) and it loads.

---
Source: https://cdpfleet.com/docs/errors · Markdown: https://cdpfleet.com/docs/errors.md · All docs for AI tools: https://cdpfleet.com/llms.txt
