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

# JavaScript SDK: errors and retries

> Handle SquareCloudAPIError in @squarecloud/api: status, code and message, the SDK's own error codes, retries, timeouts and rate limits.

Every API, network and local failure throws one class: `SquareCloudAPIError`.

Examples use the `api` client from [Creating the client](/en/sdks/js/client#creating-the-client). `appId` is the id of one of your apps: [`api.account.me()`](/en/sdks/js/client#account) lists them.

```typescript theme={"system"}
import { SquareCloudAPI, SquareCloudAPIError } from "@squarecloud/api";

try {
    await api.apps.start(appId);
} catch (error) {
    if (error instanceof SquareCloudAPIError) {
        console.error(error.status, error.code, error.message);
        console.error(error.method, error.path); // "POST" "/v2/apps/<id>/start"
    }
}
```

## `SquareCloudAPIError`

`SquareCloudAPIError` extends `Error` (it is **not** a `TypeError`).

| Property | Type | Description |
| - | - | - |
| `status` | `number` | HTTP status. `0` when no response arrived (network error, timeout, local check) |
| `code` | `ErrorCode` | The API's error code, e.g. `APP_NOT_FOUND`, or one of the SDK's codes |
| `message` | `string` | The server's explanation. When the server sent only a code, the code itself |
| `method` | `string` | HTTP method of the failed call |
| `path` | `string` | URL path of the failed call, without the query string |
| `cause` | `unknown` | The original error, for `NETWORK_ERROR` and invalid JSON |

Two failures are not wrapped:

* An aborted call rejects with the signal's `reason`. An aborted `realtime()` loop just ends.
* An upload path that cannot be opened throws the file system error.

## SDK codes

| Status | Code | When |
| - | - | - |
| 0 | `NETWORK_ERROR` | No response (DNS, connection reset, body cut off). The original error is in `cause` |
| 0 | `TIMEOUT` | No response within the [timeout](/en/sdks/js/client#timeouts) |
| 0 | `FILE_TOO_LARGE` | Local check: an upload over 100 MB or a `files.write` over 10 MB. Nothing was sent |
| 0 | `INVALID_ID` | Local check: an id that is empty, `.` or `..`. Nothing was sent |
| any | `UNKNOWN_ERROR` | A response without a code (such as a proxy error page), with the real `status` and the message `HTTP <status>`. A 2xx body that is not JSON has the message `Invalid JSON in HTTP <status> response` |

## The `ErrorCode` type

`ErrorCode` is a **type only** (no runtime object). It lists every public API code, the deprecated ones and the SDK's, plus `string & {}`, so your editor autocompletes known codes and new codes still type-check. `RATE_LIMIT` and `RATE_LIMIT_EXCEEDED` are still in the type, marked deprecated: the API now answers `RATE_LIMITED` for both.

The list of API codes grows. **Handle an unknown code by its HTTP status**:

```typescript theme={"system"}
async function start(appId: string) {
    try {
        await api.apps.start(appId);
    } catch (error) {
        if (!(error instanceof SquareCloudAPIError)) throw error;

        switch (error.code) {
            case "APP_NOT_FOUND":
                return null;
            case "CONTAINER_ALREADY_STARTED":
                return; // fine
            default:
                if (error.status === 429) return retryLater();
                if (error.status >= 500) return reportOutage(error);
                throw error;
        }
    }
}
```

## API error codes

Every other code comes from the API. The [API error reference](/en/api-reference/errors) lists each one with its HTTP status, meaning and fix, and each SDK page lists the codes its methods return most often. Any call can also answer 401 `ACCESS_DENIED` (a bad key), 403 `MISSING_SCOPE` or `RESOURCE_NOT_ALLOWED` (the [limits of the key](/en/sdks/js/client#api-key-and-scopes)), 429 (see [Rate limits](#rate-limits)) or 503 `DATABASE_UNAVAILABLE`.

`ai.chat()` errors use lowercase OpenAI codes instead (`access_denied`, `rate_limit_exceeded`, `server_overloaded`, ...). See [AI](/en/sdks/js/ai#errors).

## Retries

The SDK only retries what is safe to repeat, up to `maxRetries` times (default `2`, so up to 3 attempts):

| Retried | Methods |
| - | - |
| `NETWORK_ERROR` | `GET` only |
| 503 `UPLOAD_BUSY` | Any method |
| 503 `ANALYTICS_BUSY` | Any method |
| 503 `DATABASE_UNAVAILABLE` | `GET` only |

It **never** retries:

* `TIMEOUT`;
* any **429**: `RATE_LIMITED` can be a block of about 30 minutes, and `KEEP_CALM` is not retried either;
* other 5xx;
* AI errors.

503 `DATABASE_UNAVAILABLE` can arrive after a mutation was already applied, so the SDK does not retry it outside `GET`. Retry your own idempotent mutations if you need to.

The wait before retry `n` (starting at 0) is `min(8 s, 500 ms · 2^n) · U(0.5, 1)`: exponential backoff with 50% to 100% jitter. Set `maxRetries: 0` to turn retries off.

## Timeouts

`timeoutMs` (30 s) applies per attempt and covers the whole response. See [Timeouts](/en/sdks/js/client#timeouts) for the calls with a 120 s floor and the calls with no timeout. A timeout throws `TIMEOUT` with status `0` and is never retried.

## Rate limits

Every account has a limit of requests per 60 seconds, set by its plan ([values](/en/api-reference/limitations-and-restrictions)), and some routes have their own:

* **429 `RATE_LIMITED`**: the account or API key went over its request budget and is blocked for about 30 minutes, or an IP that keeps sending invalid keys is blocked for a short period. Also the limit of the network endpoints and `account.snapshots`.
* **429 `KEEP_CALM`**: too many calls to one route in a short time.

The SDK never retries a 429. Slow down, and wait before trying again.

## Next steps

<CardGroup cols={2}>
  <Card title="API error reference" icon="book" href="/en/api-reference/errors">
    Every error code, with its meaning and fix.
  </Card>

  <Card title="Limits and restrictions" icon="gauge" href="/en/api-reference/limitations-and-restrictions">
    The request limits of each plan.
  </Card>
</CardGroup>


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