# Errors and Status Codes

Roboflow's developer tools share a small set of error categories, surfaced differently in each tool. This page is the cross-cutting reference.

## CLI exit codes

The CLI uses four well-defined exit codes so scripts and AI agents can branch on outcome without parsing output:

| Exit code | Meaning                                                                                                      |
| --------- | ------------------------------------------------------------------------------------------------------------ |
| `0`       | Success                                                                                                      |
| `1`       | General error (bad input, network failure, unexpected server response)                                       |
| `2`       | Authentication failure (missing or invalid API key, no workspace selected)                                   |
| `3`       | Resource not found (project, version, workflow, deployment, etc. doesn't exist or isn't visible to your key) |

In `--json` mode the CLI writes structured output to stdout on success and a JSON error object to stderr on failure, leaving stdout empty so pipelines stay safe to parse:

```bash
roboflow --json project get nonexistent 2>error.json
echo $?       # 3
cat error.json
# {"error": {"message": "Project 'nonexistent' not found", "hint": "Run 'roboflow project list' to see your projects."}}
```

## SDK exceptions

The Python SDK raises Python exceptions on failure. The most common types you'll encounter:

| Exception                                            | When                                                                                                                                              |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RuntimeError`                                       | Operation is logically invalid — e.g., calling `restore()` on a project that isn't in Trash, or training on a version that hasn't been generated. |
| `ValueError`                                         | A passed argument is malformed — e.g., an unrecognized `model_format` for `Version.download()`.                                                   |
| `roboflow.adapters.rfapi.RoboflowError`              | The REST API returned a non-2xx response. The exception's string contains the server's error body.                                                |
| `roboflow.adapters.deploymentapi.DeploymentApiError` | Equivalent to `RoboflowError` for the dedicated-deployments service.                                                                              |
| `requests.exceptions.HTTPError` / `ConnectionError`  | Network-level failures (DNS, TLS, timeout).                                                                                                       |

Rule of thumb: catch `RuntimeError` for logical issues, `RoboflowError` for server-side rejections, and let everything else bubble.

```python
from roboflow.adapters import rfapi

try:
    project.restore()
except RuntimeError as e:
    print(f"Can't restore: {e}")
except rfapi.RoboflowError as e:
    print(f"Server rejected the request: {e}")
```

See [Logging and Debugging](/developer/python-sdk/logging-and-debugging.md) for how to inspect the underlying HTTP request when an exception isn't enough.

## REST API status codes

The REST API uses standard HTTP status codes. Roboflow-specific behavior:

| Status | Meaning                                                                                                                                                  |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `200`  | Success. Response body is JSON.                                                                                                                          |
| `204`  | Success, no body (used for some `PATCH` / `DELETE` endpoints).                                                                                           |
| `400`  | Malformed request — missing required field, bad shape, invalid value.                                                                                    |
| `401`  | Authentication failure. Either no `api_key`, an invalid one, or a key that lacks the required scope for the operation.                                   |
| `403`  | Forbidden. The key authenticated but doesn't have access to the target workspace or resource.                                                            |
| `404`  | Not found. The workspace, project, version, workflow, or other resource doesn't exist (or isn't visible to your key).                                    |
| `409`  | Conflict. The resource exists in a state that prevents the requested operation (for example, restoring a version whose parent project is also in Trash). |
| `423`  | Locked. Workspace billing is paused — see the response body for the reason.                                                                              |
| `429`  | Rate limited. Slow down and retry with exponential backoff.                                                                                              |
| `5xx`  | Server error. Safe to retry with backoff.                                                                                                                |

### Standard error body

Errors return JSON with at least a top-level `error` field:

```json
{
  "error": "Project 'nonexistent' not found"
}
```

Some endpoints also include a `hint` or a structured error object — see the per-endpoint documentation under [REST API](/developer/rest-api/using-the-rest-api.md) for specifics.

### Required scopes

API keys carry per-resource scopes. A 401 from a write operation often means the key doesn't have the corresponding `*:update` or `*:write` scope, even if it can read the resource. See [Scoped API Keys](/developer/authentication/scoped-api-keys.md) for the scope reference.

## Cross-tool error mapping

| Situation                     | CLI exit | SDK                                      | REST  |
| ----------------------------- | -------- | ---------------------------------------- | ----- |
| Missing / invalid API key     | `2`      | `RoboflowError` ("401")                  | `401` |
| Resource not found            | `3`      | `RoboflowError` ("404") / `RuntimeError` | `404` |
| Bad input / malformed request | `1`      | `ValueError` / `RoboflowError` ("400")   | `400` |
| Server error / transient      | `1`      | `RoboflowError` ("5xx")                  | `5xx` |

Use this table when wiring retries: a `2` / 401 should never be retried automatically (the key won't get more valid), a `3` / 404 should never be retried, but a `1` from a 5xx response is a candidate for retry with backoff.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.roboflow.com/developer/errors-and-status-codes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
