> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ocpplab.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ocpplab.io/_mcp/server.

# Errors and retries

## Errors

A `4xx` or `5xx` response raises an error that carries the status code and the response body. Each status has its own class, so you can catch only what you expect.

**`TypeScript`**

```typescript TypeScript
import { OcpplabSDK, OcpplabSDKError, OcpplabSDKTypes } from "ocpplab";

try {
    await client.evcharger.commands.getStatus({ command_id: "cmd-123" });
} catch (error) {
    if (error instanceof OcpplabSDKTypes.NotFoundError) {
        // Not delivered to the charger yet: poll again.
    } else if (error instanceof OcpplabSDKError) {
        console.error(error.statusCode, error.body);
    } else {
        throw error;
    }
}
```

**`Python`**

```python Python
from ocpplab import NotFoundError
from ocpplab.core.api_error import ApiError

try:
    client.evcharger.commands.get_status("cmd-123")
except NotFoundError:
    pass  # Not delivered to the charger yet: poll again.
except ApiError as error:
    print(error.status_code, error.body)
```

| Status | TypeScript (`OcpplabSDKTypes.*`) | Python (`ocpplab.*`)       |
| ------ | -------------------------------- | -------------------------- |
| 400    | `BadRequestError`                | `BadRequestError`          |
| 401    | `UnauthorizedError`              | `UnauthorizedError`        |
| 403    | `ForbiddenError`                 | `ForbiddenError`           |
| 404    | `NotFoundError`                  | `NotFoundError`            |
| 409    | `ConflictError`                  | `ConflictError`            |
| 412    | `PreconditionFailedError`        | `PreconditionFailedError`  |
| 422    | `UnprocessableEntityError`       | `UnprocessableEntityError` |
| 429    | `TooManyRequestsError`           | `TooManyRequestsError`     |
| 500    | `InternalServerError`            | `InternalServerError`      |
| 502    | `BadGatewayError`                | `BadGatewayError`          |
| 503    | `ServiceUnavailableError`        | `ServiceUnavailableError`  |
| 504    | `GatewayTimeoutError`            | `GatewayTimeoutError`      |

All of them extend `OcpplabSDKError` (TypeScript) or `ApiError` (Python). A request that runs out of time raises `OcpplabSDKTimeoutError` in TypeScript and `httpx.TimeoutException` in Python.

## Retries

The SDKs retry a failed request up to **2** times, with exponential backoff, when the response is `408`, `429` or `5xx`. Change it per client (`maxRetries`) or per request (`max_retries` in Python's `request_options`).

### What is never resent

A `POST` that could act twice is sent **once**, even after a `503`. If the response was lost, the first attempt may already have created the location or started the session, so a retry would do it again. This covers creates, commands and other actions.

Before you retry one of these yourself, check whether the first attempt went through:

* For deployments, call `evcharger.deploymentRuntimeOps.status`.
* For commands, list recent ones with `evcharger.commands.listResults`.

Operations that require an `Idempotency-Key` header, such as `booking.locations.create`, keep their retries: the API returns the first result for a repeated key.