# Handle errors

Canonical page: https://docs.ovok.com/python-sdk/guides/handle-errors

Every failure raises a subclass of `OvokError`. Catch the specific class you can act on and
let the rest propagate.

| Error | When |
| --- | --- |
| `OvokValidationError` | The request was malformed or invalid (400, 422), or the SDK refused to send it. |
| `OvokAuthenticationError` | Credentials are missing, invalid or expired (401). |
| `OvokPermissionError` | Signed in, but not allowed (403). |
| `OvokNotFoundError` | The resource does not exist (404). |
| `OvokConflictError` | The request conflicts with the current state (409). |
| `OvokRateLimitError` | Too many requests (429). |
| `OvokServiceError` | The server failed or was unavailable (5xx). |
| `OvokConnectionError` | No response arrived. |
| `OvokConfigError` | A client option is invalid, or this client cannot take the action. |

```python
import time

from ovok_sdk import OvokNotFoundError, OvokRateLimitError, OvokValidationError

try:
    patient = ovok.fhir.read("Patient", patient_id)
except OvokNotFoundError:
    patient = None
except OvokValidationError as error:
    for field in error.field_errors:
        print("/".join(field.path), field.message)
    raise
except OvokRateLimitError as error:
    time.sleep((error.retry_after_ms or 1_000) / 1_000)
    raise
```

Each error carries `status`, `code`, `type`, `trace_id` and `request_id`; quote `trace_id`
when reporting a failure. The client already retries safe requests that fail on the network
(`max_network_retries`, two by default).
