---
title: Errors
description: The status codes the Ysra API returns and exactly what a well-behaved client should do about each one.
---

The API uses standard HTTP status codes. Error responses carry a `detail`
field; for `422` it lists each invalid field.

| Status | Meaning | What your client should do |
|---|---|---|
| `401` | Missing, invalid or expired token. | Sign in again. |
| `404` | Unknown resource — repository, Knowledge entry, ledger cursor. | Refetch the list it came from. |
| `409` | Version conflict, or a change to something that cannot change. | Refetch, show the current state, let the person decide again. |
| `422` | The request failed validation. | Show the field-level errors. |
| `503` | The execution account is temporarily unavailable. | Retry with exponential backoff. |

## Retrying safely

Only two cases are safe to retry automatically:

- **`503`**, with exponential backoff and jitter;
- **network failures on a mutation that carries an idempotency key** — resend
  the *same* key, and the API applies the action at most once.

Everything else needs a decision: a person, or your own code with a reason.

```python title="Retry with backoff"
import random
import time

import httpx


def request_with_retry(client: httpx.Client, method: str, url: str, **kwargs) -> httpx.Response:
    for attempt in range(5):
        response = client.request(method, url, **kwargs)
        if response.status_code != 503:
            return response
        # Jitter spreads retries from many clients so they don't arrive together.
        time.sleep(min(30, 2**attempt) + random.random())
    response.raise_for_status()
    return response
```

## Validation errors

Each entry in `detail` names the field that failed and why. Map it back to the
form input that produced it, and show the message next to that input.
