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

# Error handling in the openmem SDK

> All OMP exceptions inherit from OMPError. Learn the full error hierarchy, standard codes, and how to write consistent error-handling logic across any provider.

The OMP Python SDK raises typed exceptions so you can write consistent error-handling logic regardless of which provider is underneath. All exceptions inherit from `OMPError`, carry a standard `code`, `type`, `provider`, and `request_id`, and mirror the error envelope that the OMP HTTP API returns on failure.

## Import

```python theme={null}
from openmem import (
    OMPError,
    UnauthorizedError,
    ScopeDeniedError,
    NotFoundError,
    InvalidRequestError,
    RateLimitedError,
    UnsupportedCapabilityError,
    ProviderError,
    UnsupportedProviderError,
)
```

***

## Error hierarchy

All exceptions extend `OMPError(Exception)`. Each subclass maps to a specific `error.code` value in the OMP wire format.

| Exception class              | `error.code`             | `error.type`     | When raised                                  |
| ---------------------------- | ------------------------ | ---------------- | -------------------------------------------- |
| `UnauthorizedError`          | `unauthorized`           | `auth`           | Missing or invalid credentials               |
| `ScopeDeniedError`           | `scope_denied`           | `auth`           | App lacks the required scope permission      |
| `NotFoundError`              | `not_found`              | `not_found`      | Memory ID does not exist                     |
| `InvalidRequestError`        | `invalid_request`        | `invalid`        | Malformed or missing request parameters      |
| `RateLimitedError`           | `rate_limited`           | `rate_limited`   | Provider rate limit exceeded                 |
| `UnsupportedCapabilityError` | `unsupported_capability` | `invalid`        | Verb not supported by this provider          |
| `ProviderError`              | `provider_error`         | `provider_error` | Backend-specific error                       |
| `UnsupportedProviderError`   | `invalid_request`        | `invalid`        | Unknown provider string passed to `Memory()` |

All instances expose the following attributes:

* `e.message` — human-readable description
* `e.code` — machine-readable error code string
* `e.type` — error category (`auth`, `not_found`, `invalid`, `rate_limited`, `provider_error`)
* `e.provider` — the provider that raised the error, or `None`
* `e.request_id` — the provider-assigned request ID for tracing, or `None`

***

## Common error handling pattern

```python theme={null}
from openmem import Memory, OMPError, NotFoundError, RateLimitedError
import time

mem = Memory(provider="postgres", url="postgresql://localhost/omp")

try:
    record = mem.get("mem_does_not_exist")
except NotFoundError:
    print("Memory not found")
except RateLimitedError:
    time.sleep(1)
    # retry
except OMPError as e:
    print(f"OMP error {e.code}: {e.message}")
    print(f"Provider: {e.provider}, Request ID: {e.request_id}")
```

Catching `OMPError` as the final handler gives you a safe fallback for any OMP-originated exception.

***

## Handling auth errors

```python theme={null}
from openmem import Memory, UnauthorizedError, ScopeDeniedError

mem = Memory(provider="mem0", api_key="...")

try:
    results = mem.search("health records", user_id="u1", scope="health/*")
except UnauthorizedError:
    print("Invalid or missing API key — check your credentials")
except ScopeDeniedError as e:
    print(f"Permission denied: {e.message}")
    # Prompt the user to grant access to the required scope
```

***

## Handling unsupported capabilities

Not all providers support every OMP verb. You can either check capabilities upfront or catch `UnsupportedCapabilityError` at call time:

```python theme={null}
from openmem import Memory, UnsupportedCapabilityError

mem = Memory(provider="mem0", api_key="...")

# Option A: check upfront
caps = mem.capabilities()
if caps.features.supports_audit:
    entries = mem.audit(user_id="u1")

# Option B: catch at call time
try:
    entries = mem.audit(user_id="u1")
except UnsupportedCapabilityError:
    entries = []
```

***

## Error envelope structure

When an OMP-native HTTP server returns an error, it uses this JSON envelope. The SDK parses this envelope and raises the matching exception class automatically.

```json theme={null}
{
  "error": {
    "code": "not_found",
    "message": "Memory mem_abc123 not found",
    "type": "not_found",
    "provider": "postgres",
    "request_id": "req_xyz"
  }
}
```

You can reconstruct any `OMPError` subclass from a raw error dict using `OMPError.from_response_dict()`:

```python theme={null}
raw = {
    "error": {
        "code": "not_found",
        "message": "Memory mem_abc123 not found",
        "type": "not_found",
        "provider": "postgres",
        "request_id": "req_xyz",
    }
}
exc = OMPError.from_response_dict(raw)
# exc is a NotFoundError instance
```

***

## Provider consistency guarantee

OMP guarantees that the same logical condition raises the same exception class regardless of which provider is active. For example, requesting a non-existent memory ID always raises `NotFoundError` — whether you're using the postgres adapter, the mem0 adapter, or a native passthrough provider. You never need to write provider-specific error handling.

***

## Ingestion timeout

`ProviderError` with `code="ingestion_timeout"` is a special case raised by async-ingestion providers (mem0, supermemory) when a memory fails to become searchable within the polling timeout. This is distinct from a generic backend failure.

```python theme={null}
from openmem import Memory, ProviderError

mem = Memory(provider="mem0", api_key="...")
record = mem.add(content="prefers dark mode", user_id="u1")

try:
    mem.wait_for_ingest([record.id], user_id="u1", timeout=10.0)
except ProviderError as e:
    if e.code == "ingestion_timeout":
        print("Memory was stored but not yet indexed — retry search later")
    else:
        raise
```
