# Errors and limits

Source: https://heaven.dev/docs/errors

Every error has a kind for your code to check and a message to show people. The message says what to do next.

## The error object

409:

```json
{
  "version": 1,
  "error": {
    "kind": "conflict",
    "message": "This request ID was already used for a different request. Use a new --request-id.",
    "request_id": "create-my-site",
    "operation_id": "8540e6f2-9f39-4d39-89b5-eeac80d0ac97"
  }
}
```

- `kind` string: What went wrong, from the list below. Your code should check this.
- `message` string: A sentence to show people, with the specific problem and the next step. Its wording can change, so don't parse it.
- `request_id` string: The change's `Idempotency-Key`, when it had one.
- `operation_id` string: The operation to read, when there is one.
- `retry_after` integer: For `rate_limited`, the seconds to wait. It's also sent as the `Retry-After` header.
- `url` string: A Stripe page where you can pay, for some `payment_required` errors.
- `action` object: Present when the message suggests a command. `command` is its name (`pool start`), and `line` is the full command from the message (`pool start web`), so an app can show its own button for it.

## Kinds

| Kind | HTTP | Means | Do |
| --- | --- | --- | --- |
| `invalid` | 400 | A missing or malformed field, value or size. | Fix the request. |
| `denied` | 401, 403 | The credential is missing, expired or not allowed this command. | Check the key and its `commands`. |
| `not_found` | 404 | Nothing by that name or ID that you can reach. | Check the name. Another account's resources are `not_found` too. A one-time link that was already used or has expired returns `not_found` with HTTP `410`. |
| `conflict` | 409 | It clashes with the current state, such as a taken name, a stopped Computer or a reused `Idempotency-Key`. | Read the message, then change the state or the request. |
| `over_capacity` | 409 | A limit was reached, such as not enough capacity on the server, too many Computers in the pool, or too many keys. | Buy [capacity](https://heaven.dev/docs/pools#capacity), or stop or shrink a pool. |
| `access_list_full` | 409 | A share or key would grow a server's access list past what it can hold. | Share with a team or the organization instead of person by person. |
| `payment_required` | 402 | Payment is needed first. The balance can't cover the first hour of capacity, a pool's capacity has lapsed or its storage is unpaid, or a card was declined. | Add money, or open the returned `url`. |
| `rate_limited` | 429 | You sent commands faster than your rate limit. Nothing changed. | Wait `retry_after` seconds. |
| `busy` | 429 | Too many of your requests at once, or the server is at capacity. Nothing changed. | Retry shortly. |
| `unknown` | 503 | A change's outcome couldn't be confirmed, so it may have happened. Or a read failed, and its message says nothing changed. | For a change, [find out what happened](https://heaven.dev/docs/operations#unknown): read the operation, or send it again with the same `Idempotency-Key`. Retry a read. |
| `unavailable` | 503 | Refused before anything changed, for a reason that may pass. For example, the server isn't accepting changes, the pool is moving between servers, a Computer's console or mail couldn't be reached, or a provider isn't set up. | Retry later. The message says what to wait for. |

## Rate limits

Limits are per person and shared by the API, the dashboard and SSH, so one runaway script doesn't slow the rest of your team.

| What | Rate | Burst |
| --- | --- | --- |
| All commands | 20 a second | 300 |
| Changes (create, start, snapshots, domains, ports, pools, billing…) | 1 a second | 60 |
| Revoking a key or sign-in (`api-key remove`, `ssh-key remove`, `sign-in end-all`), counted for each key and sign-in separately | 1 a second | 60 |
| Requests in progress at once | 16. Another request waits up to two seconds for one to finish, then returns `busy`. |

Revoking counts only against its own limit, so a leaked key that uses up your other limits can't stop you removing it. Someone clicking in the dashboard never comes close, and fifty creates at once fit in the burst.

A change that names several Computers, or several static addresses, counts once for each. Heaven accepts such a request whenever it would accept a single command, whatever the request's size. If it names more than you have left, your next commands wait until the limit has refilled by that many.

> Waiting on an operation? Use `wait=true` or a [stream](https://heaven.dev/docs/operations#streaming) instead of polling quickly. A wait in progress doesn't count against the 16.

## Size limits

| What | Limit |
| --- | --- |
| A `POST` body | 512 KiB of JSON; 2 MiB for `exec` |
| `exec` output, not streamed | 1 MiB, within 30 seconds |
| `exec` streamed | An hour, with no limit on output or input |
| `stdin` in JSON | 1 MiB. Send more as the request body. |
| Setup script | 10 KiB |
| Feedback text | 16 KiB |
