# Errors and rate limits

Errors come back as JSON with a readable message and a stable code to branch on.

```json
{ "error": "This API key doesn't control this output", "code": "forbidden" }
```

## Error codes

| Status | Code | What happened |
| --- | --- | --- |
| 400 | `invalid_request` | The body or path doesn't match the schema. The message says which field is wrong. |
| 401 | `unauthorized` | No API key, or the key is wrong or revoked. |
| 403 | `forbidden` | The key doesn't control this output. |
| 404 | `not_found` | No such output or instance, or it isn't in your workspace. |
| 409 | `default_instance` | A component's default instance can't be removed. |
| 422 | `command_failed` | A command in a batch couldn't run, so none did. See below. |
| 429 | `rate_limited` | Too many commands. Wait the number of seconds in `Retry-After`. |

## Failed commands

A batch runs all or nothing. If any command can't run, nothing changes on air, and the response says which command failed by its position in the batch, counting from 0:

```json
{ "error": "No component lower-thrid", "code": "command_failed", "index": 1 }
```

Common reasons: an id that isn't in the version the output plays, an instance that belongs to another component, sending both `data` and `instance` on `in`, or an output with no composition yet.

## Rate limits

API keys can send 200 command batches every 10 seconds each. Past that, [Run commands](https://docs.airframe.tv/api/run-commands) answers `429` with a `Retry-After` header. Put many changes in one batch rather than sending them one by one: a batch of up to 100 commands counts once.
