# Errors

> The error codes the API returns, and what each one means.

When a request fails, the API answers with an HTTP error status and a JSON body like this one:

```json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Not found.",
    "details": {}
  }
}
```

- `code` names what went wrong. Codes never change once they ship, so branch on the code.
- `message` is a sentence you can show a person or pass to an agent. Its wording can change.
- `details` appears on some codes with more context, such as the problems in a runner order.

When a code means you can try again later, such as `RATE_LIMITED`, the response also has a `Retry-After` header with the seconds to wait. The [MCP server](/docs/reference/mcp) passes the message and the code to your agent.

## Codes

| Code | Status | Message |
| --- | --- | --- |
| `AGENT_NOT_ALLOWED` | 403 | Agent tokens can't call this route. |
| `CANNOT_DELETE_SELF` | 400 | You can't delete your own account here. |
| `CANNOT_DEMOTE_SELF` | 400 | You can't remove your own operator role. |
| `DEVICE_CODE_CLAIMED` | 403 | Another account already approved or denied this request. Run `relayrunner connect` again for a new code. |
| `DEVICE_CODE_EXPIRED` | 400 | That code has expired. Run `relayrunner connect` again for a new one. |
| `DEVICE_CODE_INVALID` | 400 | That code doesn't match a sign-in request. Check it against your terminal. |
| `DEVICE_CODE_USED` | 409 | That code has already been used. |
| `FORBIDDEN` | 403 | You don't have access to that. |
| `GITHUB_APP_NOT_CONFIGURED` | 500 | The GitHub App isn't set up. |
| `GITHUB_RATE_LIMITED` | 503 | GitHub's API limit was reached. Try again shortly. |
| `GITHUB_UNAVAILABLE` | 502 | GitHub didn't answer. Try again shortly. |
| `INTERNAL_ERROR` | 500 | Something went wrong on our side. |
| `INVALID_REQUEST` | 400 | The request isn't valid. |
| `INVALID_TOKEN` | 401 | The token is invalid, expired or revoked. |
| `LEGAL_TERMS_OUTDATED` | 409 | The terms changed since you opened this page. Reload it to read the new version. |
| `MACHINE_NOT_OWNED` | 403 | Only a machine with an owner can do this. |
| `METHOD_NOT_ALLOWED` | 405 | That method isn't allowed here. |
| `NO_ACTIVE_WORKSPACE` | 409 | Pick a workspace first. |
| `NOT_A_MEMBER` | 403 | You aren't a member of that workspace. |
| `NOT_FOUND` | 404 | Not found. |
| `PAYLOAD_TOO_LARGE` | 413 | The request body is too large. |
| `PRICE_EXISTS` | 409 | That rate already has a price from that day. Remove it first to correct it. |
| `PRICE_INVALID` | 400 | Check the price and date. |
| `PROVIDER_EXISTS` | 409 | There's already a provider with that id. |
| `PROVIDER_ID_INVALID` | 400 | Use lowercase letters, numbers and dashes for the id. |
| `PROVIDER_INVALID` | 400 | Fill in a name, summary and labels, and use https:// links. |
| `PROVIDER_NOT_CONNECTED` | 404 | That provider isn't connected. |
| `PROVIDER_PREFIX_TAKEN` | 409 | Another provider, or GitHub's own runners, already use labels like that. |
| `PROVIDER_PREFIXES_INVALID` | 400 | Add at least one label prefix, three or more characters each. |
| `PROVIDER_TOKEN_REJECTED` | 400 | The provider didn't accept that token. Check it and its scope. |
| `PROVIDER_UNKNOWN` | 400 | There's no provider with that id. |
| `PROVIDER_UNREACHABLE` | 502 | The provider's API didn't answer. Try again shortly. |
| `RATE_LIMITED` | 429 | Too many requests. Try again shortly. |
| `RUNNER_ORDER_INVALID` | 400 | The runner order isn't valid. |
| `TELEMETRY_ENDPOINT_INVALID` | 400 | Use an https URL on the internet, like https://api.honeycomb.io. |
| `TELEMETRY_HEADER_MISSING` | 400 | Enter a value for each header. |
| `TELEMETRY_NOT_CONFIGURED` | 404 | Telemetry isn't set up for this workspace. |
| `TOKEN_STORAGE_UNAVAILABLE` | 503 | Saving provider tokens isn't set up on this server yet. |
| `UNAUTHENTICATED` | 401 | Sign in first. |
| `USER_HAS_SHARED_WORKSPACES` | 409 | The user is in workspaces with other members. Remove them from those first. |
| `WEBHOOK_ENQUEUE_FAILED` | 503 | The delivery couldn't be queued. Redeliver it from the App's settings. |
| `WEBHOOK_SECRET_NOT_CONFIGURED` | 500 | The webhook secret for this App isn't set up on this server. |
| `WEBHOOK_SIGNATURE_INVALID` | 401 | The webhook signature is missing or doesn't match the App's secret. |
| `WEBSOCKET_REQUIRED` | 426 | Connect with a WebSocket upgrade. |
| `WORKSPACE_REQUIRED` | 409 | This token reads more than one workspace. Name one with the x-relayrunner-workspace header. |
