# Errors

> The error format and the codes you're most likely to see.

Source: https://docs.coline.app/api/errors

Every error has the same shape and a matching HTTP status:

```json
{
  "error": {
    "code": "API_KEY_SCOPE_FORBIDDEN",
    "message": "API key is missing required scope: files.write"
  }
}
```

The code is also in the `x-coline-error-code` response header. Branch on `code`, not on `message`; messages are written for people and can change.

## Status codes

| Status | Meaning                                                                                      | Retry?                                                |
| ------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| `400`  | The request is malformed or fails validation                                                 | No, fix the request                                   |
| `401`  | Missing, unknown or expired credentials                                                      | Refresh the OAuth token, then retry once              |
| `402`  | Not enough API credits for a metered call                                                    | After adding credits                                  |
| `403`  | Authenticated, but not allowed: missing scope, wrong workspace, or no access to the resource | No                                                    |
| `404`  | The resource doesn't exist, or you can't see it                                              | No                                                    |
| `409`  | Conflicts with the current state, such as a stale version                                    | Read the latest state first                           |
| `429`  | Rate limited                                                                                 | Yes, after `X-RateLimit-Reset`                        |
| `500`  | Something failed on Coline's side                                                            | Yes, with backoff. Read back before retrying a create |

## Common codes

### Authentication and access

| Code                         | Status | Meaning                                                                           |
| ---------------------------- | ------ | --------------------------------------------------------------------------------- |
| `UNAUTHORIZED`               | 401    | No credentials, or you need to sign in                                            |
| `INVALID_TOKEN`              | 401    | The OAuth access token is unknown or expired                                      |
| `API_KEY_SCOPE_FORBIDDEN`    | 403    | The API key lacks a scope the route needs                                         |
| `OAUTH_SCOPE_FORBIDDEN`      | 403    | The OAuth token lacks a scope the route needs                                     |
| `API_KEY_WORKSPACE_MISMATCH` | 403    | The key belongs to a different workspace than the one in the path                 |
| `USER_IDENTITY_REQUIRED`     | 403    | The route acts for a person; use an OAuth token, not an API key                   |
| `WORKSPACE_REQUIRED`         | 400    | The route needs a workspace in the path                                           |
| `WORKSPACE_NOT_FOUND`        | 404    | No workspace with that slug or ID that you can access                             |
| `WORKSPACE_INACTIVE`         | 403    | The workspace is suspended or deleted                                             |
| `WORKSPACE_ARCHIVED`         | 403    | The workspace is archived and read-only                                           |
| `MUTATION_ORIGIN_REQUIRED`   | 403    | A write was sent without a bearer token and without a same-origin browser session |

### Requests

| Code                   | Status | Meaning                                                           |
| ---------------------- | ------ | ----------------------------------------------------------------- |
| `VALIDATION_ERROR`     | 400    | The body or query failed validation; the message says which field |
| `BAD_REQUEST`          | 400    | The request can't be processed as sent                            |
| `CONFLICT`             | 409    | The change conflicts with the current state                       |
| `RATE_LIMIT_EXCEEDED`  | 429    | Too many requests in the current minute                           |
| `INSUFFICIENT_CREDITS` | 402    | The workspace's API credit balance can't cover the call           |
| `MODEL_NOT_FOUND`      | 400    | Unknown Tab model                                                 |
| `INTERNAL_ERROR`       | 500    | Unexpected failure                                                |

### Resources

| Code                                     | Status | Meaning                                                     |
| ---------------------------------------- | ------ | ----------------------------------------------------------- |
| `NOT_FOUND`                              | 404    | Generic not found                                           |
| `FILE_NOT_FOUND`, `DRIVE_NOT_FOUND`      | 404    | The file or drive doesn't exist or isn't visible to you     |
| `TASK_NOT_FOUND`, `TASKBOARD_NOT_FOUND`  | 404    | The task or board doesn't exist or isn't visible to you     |
| `PARENT_NOT_FOUND`, `INVALID_PARENT`     | 400    | The target folder doesn't exist or can't hold the file      |
| `UPLOAD_NOT_FOUND`                       | 404    | The upload ID is unknown or expired                         |
| `APP_NOT_FOUND`, `APP_INSTALL_NOT_FOUND` | 404    | The app doesn't exist, or isn't installed in this workspace |
| `APP_MANIFEST_INVALID`                   | 400    | A pushed app version failed manifest validation             |

### OAuth

| Code                   | Status | Meaning                                                                   |
| ---------------------- | ------ | ------------------------------------------------------------------------- |
| `INVALID_CLIENT`       | 401    | Unknown client, or the secret doesn't match                               |
| `INVALID_REDIRECT_URI` | 400    | The redirect URL isn't registered for the client                          |
| `INVALID_GRANT`        | 400    | The code or refresh token is expired, already used, or for another client |

Routes return other, more specific codes too. Treat any code you don't recognize by its HTTP status.
