> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minerva.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Error handling

> One exception hierarchy. Specific subclasses where you'd actually want to branch on the failure.

All SDK errors derive from `MinervaError`. The hierarchy lets you catch
broadly (any SDK error) or narrowly (specific failure mode), and most carry
context attributes so you can build a useful UI without parsing message
strings.

## The hierarchy

```
Exception
└── MinervaError                          ← catch-all
    ├── MinervaConfigError                ← misconfiguration
    ├── MinervaValidationError            ← boundary failures, raised locally
    ├── MinervaAuthError                  ← 401/403 (bad key, not entitled)
    ├── MinervaRateLimitError             ← 429.  .retry_after
    └── MinervaAPIError                   ← other 4xx/5xx.  .status_code, .api_request_id, .body
```

## Quick reference

| Exception                | When                                                   | Carries                                    |
| ------------------------ | ------------------------------------------------------ | ------------------------------------------ |
| `MinervaValidationError` | Bad input — raised locally, before the call            | —                                          |
| `MinervaAuthError`       | 401/403 — invalid key or not entitled to this endpoint | —                                          |
| `MinervaRateLimitError`  | 429 — back off and retry                               | `.retry_after` (seconds)                   |
| `MinervaAPIError`        | Other 4xx/5xx                                          | `.status_code`, `.api_request_id`, `.body` |
| `MinervaConfigError`     | Misconfiguration                                       | —                                          |

## Insufficient credits (402)

When your Minerva credits are exhausted, the server returns HTTP 402 with `code` `"insufficient_credits"`. This surfaces as `MinervaAPIError` with `status_code=402`. The response body's `details` object includes `records_remaining` (an estimate of how many records you have left based on your credit balance) and `records_requested` (the batch size that was rejected):

```python theme={null}
from minerva import MinervaAPIError

try:
    result = mc.api.enrich(batch)
except MinervaAPIError as e:
    if e.status_code == 402:
        details = (e.body or {}).get("details", {})
        print(f"Minerva credits exhausted. "
              f"~{details.get('records_remaining')} records remaining, "
              f"requested: {details.get('records_requested')}")
    else:
        raise
```

## Rate limits

```python theme={null}
import time
from minerva import MinervaRateLimitError

while True:
    try:
        result = mc.api.enrich(batch)
        break
    except MinervaRateLimitError as e:
        time.sleep(e.retry_after or 1)
```

`retry_after` is the server's hint in seconds. Fall back to a sane default
(1s) if the server didn't supply one.

## Server errors

```python theme={null}
from minerva import MinervaAPIError

try:
    mc.api.enrich(records)
except MinervaAPIError as e:
    print(f"server returned {e.status_code}")
    if e.api_request_id:
        print(f"quote to support: {e.api_request_id}")
```

`api_request_id` is the server's trace ID — quote it when reporting issues to
support. Responses are forward-compatible: fields the server adds later won't
break an older SDK.

## Validation errors

`MinervaValidationError` is raised **locally** before any HTTP call — bad
payload shape, over-the-limit record counts, missing required fields:

```python theme={null}
from minerva import MinervaValidationError

try:
    mc.api.enrich([])     # 0 records — must be ≥ 1
except MinervaValidationError as e:
    print("caught before any API call:", e)
```

Use `dry_run=True` to trigger the same validation without committing to the
call — see [Validation & dry\_run](/sdk/guides/validation-dry-run).

## Catch-all

```python theme={null}
from minerva import MinervaError

try:
    mc.api.enrich(records)
except MinervaError as e:
    log.error("Minerva call failed", exc_info=e)
    raise
```

<Note>
  `MinervaAuthError` is also raised when no `MINERVA_API_KEY` is set (or
  `api_key=` passed) — that's a local check, before any HTTP call. The error
  message tells you exactly what's missing.
</Note>
