# Errors (/docs/sdk/errors)



Every failed API call in the TypeScript SDK throws a `CrowNestApiError`.
The error carries the HTTP status and a stable, machine-readable code so
you can branch on failures without parsing messages.

## CrowNestApiError [#crownestapierror]

`CrowNestApiError` extends `Error` with structured fields:

| Property  | Type                  | Description                                                               |
| --------- | --------------------- | ------------------------------------------------------------------------- |
| `status`  | `number`              | HTTP status code.                                                         |
| `code`    | `string`              | Stable error code in lowercase snake\_case, for example `quota_exceeded`. |
| `message` | `string`              | Human-readable description.                                               |
| `details` | `object \| undefined` | Additional context for some errors.                                       |

```ts
import { createCrowNestClient, CrowNestApiError } from "@crownest/sdk";

const client = createCrowNestClient();

try {
  await client.sandboxes.create({ ttlMs: 60 * 60 * 1000 });
} catch (error) {
  if (error instanceof CrowNestApiError) {
    console.error(error.status, error.code, error.message);
    if (error.code === "sandbox_ttl_exceeded") {
      // retry with a smaller ttlMs
    }
  } else {
    throw error;
  }
}
```

## Non-zero exit codes don't throw [#non-zero-exit-codes-dont-throw]

A command that runs to completion with a non-zero exit code is a
successful API call. `commands.run` resolves normally; the SDK only throws
when the API itself fails (for example, the sandbox is destroyed). A command
that exceeds its `timeoutMs` resolves with `status` `"timed_out"`.

```ts
const result = await sandbox.commands.run("false");
console.log(result.status); // "exited"
console.log(result.exitCode); // 1 — no error thrown
```

Always check `command.status` and `command.exitCode` to decide whether
the process succeeded.

## Common error codes [#common-error-codes]

| Code                               | HTTP    | Meaning                                                                       |
| ---------------------------------- | ------- | ----------------------------------------------------------------------------- |
| `invalid_request`                  | 400     | Malformed request or validation failure.                                      |
| `sandbox_ttl_exceeded`             | 400     | Requested `ttlMs` exceeds your plan limit.                                    |
| `reserved_env_key`                 | 400     | An env key uses the reserved `CROWNEST` prefix.                               |
| `unauthorized` / `invalid_api_key` | 401     | Missing, invalid, or revoked credentials.                                     |
| `forbidden`                        | 403     | Missing scope or no access to the resource.                                   |
| `org_suspended`                    | 403     | The organization is suspended.                                                |
| `not_found`                        | 404     | The resource doesn't exist or isn't visible to you.                           |
| `idempotency_key_reused`           | 409     | The same idempotency key was used with a different request.                   |
| `idempotency_request_in_progress`  | 409     | The original request with this key is still running.                          |
| `sandbox_destroyed`                | 409     | The sandbox is already destroyed.                                             |
| `file_too_large`                   | 413     | Content exceeds the 256 KB direct file write limit.                           |
| `quota_exceeded`                   | 429     | A plan quota was reached.                                                     |
| `rate_limited`                     | 429     | The request rate limit was reached (120 requests per 60 seconds per API key). |
| `resource_allocation_failed`       | 500/503 | Internal resource allocation or startup failed.                               |
| `unsupported_runtime_option`       | 500     | Runtime option or placement is not supported.                                 |
| `stream_gap`                       | 409     | The requested command log position is no longer available.                    |
| `preview_unavailable`              | 502     | The preview port isn't responding.                                            |

File operations can also fail with `path_outside_workspace`,
`path_is_directory`, `path_not_directory`, `file_not_found`,
`file_already_exists`, `parent_directory_not_found`,
`directory_not_empty`, and `invalid_file_encoding`. See
[Files](/docs/sdk/files) for where each applies.

## Retries and idempotency [#retries-and-idempotency]

The create-style operations — `sandboxes.create`, `commands.run`, and
`artifacts.create` — accept an `idempotencyKey`.
The SDK generates one automatically when you don't pass it, so retrying a
failed call with the same key never duplicates work.

Idempotency keys are retained for 24 hours and scoped to the org,
credential, method, and route:

* Replaying the same key with the same request returns the original
  response.
* Reusing the key with a different request fails with
  `idempotency_key_reused` (409).
* Retrying while the original request is still running fails with
  `idempotency_request_in_progress` (409).

We recommend this retry policy:

* Retry `429` (`rate_limited`, `quota_exceeded`) and `5xx` errors with
  exponential backoff.
* Pass your own `idempotencyKey` when you retry create operations across
  process restarts, so the key survives the restart.
* Don't retry `4xx` validation errors (`invalid_request`,
  `sandbox_ttl_exceeded`, `forbidden`) — fix the request instead.
* Treat `sandbox_destroyed` (409) as terminal for that sandbox: create a
  new one.

## Next steps [#next-steps]

* [Sandboxes](/docs/sdk/sandboxes) — create operations that accept
  idempotency keys.
* [Commands](/docs/sdk/commands) — command status and exit codes.
* [API error reference](/docs/api/errors) — the REST error envelope.
