> For the complete documentation index, see [llms.txt](https://docs.robincompute.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.robincompute.org/api-reference/errors.md).

# Errors

Failures come back as conventional HTTP status codes. Every failed request also carries a JSON body: a stable, machine-readable `code` paired with a `message` written for humans.

***

## Error response format

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your credit balance (4 credits) is insufficient for the Standard tier (8 credits required).",
    "type": "payment_error",
    "param": null,
    "docs": "https://docs.robincompute.org/api-reference/errors#insufficient_credits"
  }
}
```

| Field     | Description                                                    |
| --------- | -------------------------------------------------------------- |
| `code`    | Stable identifier; branch your program logic on this           |
| `message` | Plain-language account of what went wrong                      |
| `type`    | Broad category the error falls into                            |
| `param`   | The request parameter that triggered the failure, when one did |
| `docs`    | Deep link into this page, anchored at the matching error       |

***

## HTTP status codes

| Status | Category            | When it occurs                                                                        |
| ------ | ------------------- | ------------------------------------------------------------------------------------- |
| `400`  | Bad request         | The body failed to parse, lacks a required field, or holds an invalid value           |
| `401`  | Authentication      | The API key is missing or not recognized                                              |
| `402`  | Payment             | Not enough credits on the wallet                                                      |
| `403`  | Forbidden           | The key is suspended, or the operation is off limits                                  |
| `404`  | Not found           | No job, model, or webhook matches the identifier                                      |
| `409`  | Conflict            | The resource already exists or its state conflicts with the operation                 |
| `422`  | Unprocessable       | The request is well-formed but fails a semantic rule                                  |
| `429`  | Too many requests   | You hit the per-IP burst limit on the API layer itself; unrelated to network capacity |
| `500`  | Server error        | Something failed internally; a retry usually succeeds                                 |
| `503`  | Service unavailable | No worker is hosting the requested model right now                                    |
| `504`  | Gateway timeout     | The job timed out and your credits came back                                          |

***

## Error codes

### `invalid_api_key`

The key you sent never existed or was revoked.

**Status:** 401\
**Action:** Issue a fresh key from Settings.

***

### `missing_api_key`

The request carried no `Authorization` header.

**Status:** 401\
**Action:** Add `Authorization: Bearer rcompute_live_your_key_here` to every request.

***

### `key_suspended`

This key is suspended. That happens when an account gets flagged for abuse.

**Status:** 403\
**Action:** Reach out to <contact@robincompute.org>.

***

### `insufficient_credits`

The wallet behind this key holds fewer credits than the requested tier costs.

**Status:** 402\
**Action:** Top up at `robincompute.org/app`, or pick a model from a cheaper tier.

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your credit balance (4 credits) is insufficient for the Standard tier (8 credits required).",
    "type": "payment_error",
    "details": {
      "credits_remaining": 4,
      "credits_required": 8,
      "tier": "standard"
    }
  }
}
```

***

### `model_not_found`

The request's `model` field matches no model ID the network knows about.

**Status:** 400\
**Action:** Fetch `GET /v1/models` and pick an ID from the response.

***

### `no_workers_available`

Zero workers are hosting the model you asked for right now. The condition is transient; it clears as workers come online.

**Status:** 503\
**Action:** Wait out the `retry_after` interval and try again, or switch models.

```json
{
  "error": {
    "code": "no_workers_available",
    "message": "No workers are currently available for llama-3.3-70b. Try again in approximately 30 seconds.",
    "type": "capacity_error",
    "details": {
      "model": "llama-3.3-70b",
      "retry_after": 30
    }
  }
}
```

***

### `job_timeout`

The 120-second window closed before any worker finished the job. The escrowed credits came back automatically; the `refund_tx` in the details is the refund's on-chain receipt.

**Status:** 504\
**Action:** Send the request again; refunded credits are usable right away. Repeated timeouts on one model mean its worker pool is thin.

```json
{
  "error": {
    "code": "job_timeout",
    "message": "The inference job timed out after 120 seconds. Your credits have been refunded.",
    "type": "timeout_error",
    "details": {
      "job_id": "job_8fx2kp3m9qrstvwxyz",
      "credits_refunded": 8,
      "refund_tx": "0x5e08c3b71a94f2d6580b1ce9f43a07d218e6c5049fb3a827d15e90cb46281f7a"
    }
  }
}
```

***

### `invalid_request`

The body could not be parsed, or a required field is missing.

**Status:** 400\
**Action:** The `param` field names the offender; start there.

***

### `context_length_exceeded`

The messages in the request, taken together, exceed what the chosen model's context window can hold.

**Status:** 400\
**Action:** Trim the conversation, or move to a model with more context. The `context_window` field in `GET /v1/models` shows each model's limit.

***

### `dispute_window_expired`

The dispute arrived after the 60-second window closed.

**Status:** 422\
**Action:** None available. A dispute must land within 60 seconds of the final output token, and the window does not extend.

***

## Retrying safely

Retry freely on any 5xx and on `no_workers_available` (503). Everything else is a flaw in the request itself; resending the same payload fails the same way.

Recommended retry strategy:

```python
import time
import httpx

def call_with_retry(client, payload, max_retries=3):
    for attempt in range(max_retries):
        response = client.post("/v1/chat/completions", json=payload)
        
        if response.status_code == 200:
            return response
        
        error = response.json().get("error", {})
        code = error.get("code")
        
        if response.status_code == 503 and code == "no_workers_available":
            retry_after = error.get("details", {}).get("retry_after", 10)
            time.sleep(retry_after)
            continue
        
        if response.status_code >= 500:
            time.sleep(2 ** attempt)
            continue
        
        # Do not retry 4xx responses; surface them instead
        response.raise_for_status()
    
    raise Exception(f"Request failed after {max_retries} attempts")
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.robincompute.org/api-reference/errors.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
