Python SDK
Error Handling
The Python client raises exactly six exception classes. Catch them deliberately. The base class (MemorySyncError) carries the HTTP status, the parsed response body, and the server\u2019sX-Request-ID on every instance — so when something blows up in production you have everything support needs to triage.
The class tree
TEXT
MemorySyncError # base class — also raised on network/timeout├ AuthError # 401 / 403├ NotFoundError # 404├ ValidationError # 400, 409, 422, and client-side guards├ RateLimitError # 429 (carries retry_after_seconds)└ ServerError # 5xx
Every error carries the same context
| Attribute | Type | Meaning |
|---|---|---|
str(exc) | str | Human-readable message — usually the server’s detail field. |
status_code | int | None | HTTP status; None for transport errors. |
response | Any | Parsed JSON body if the server returned one. |
request_id | str | None | Server-assigned request id, also in the X-Request-ID header. |
Class-specific attributes
| Class | Extra attribute | Use it for |
|---|---|---|
RateLimitError | retry_after_seconds | How long to sleep before the next attempt. Comes from the server. |
ValidationError | — | Inspect .response for the offending field; do not retry. |
AuthError | — | Treat as fatal; rotate or fix the key. |
NotFoundError | — | The id you passed does not exist or is not visible to this key. |
ServerError | — | Temporary server-side problem. Safe to retry with backoff. |
MemorySyncError | — | Network failure or request timeout. Retry like ServerError. |
The idiomatic try/except
PYTHON
from memorysync.errors import (AuthError, NotFoundError, ValidationError,RateLimitError, ServerError, MemorySyncError,)try:m = client.get(memory_id=42)except NotFoundError:m = None # genuinely missingexcept ValidationError as e:raise # caller bug — surface itexcept AuthError:raise # ops issue — alertexcept RateLimitError as e:sleep(e.retry_after_seconds); retry()except (ServerError, MemorySyncError) as e: # transientbackoff_and_retry(e)
A small retry helper you can paste
PYTHON
import time, randomfrom memorysync.errors import RateLimitError, ServerError, MemorySyncErrordef with_retry(fn, *, attempts=3):for i in range(attempts):try:return fn()except RateLimitError as e:if i == attempts - 1:raisetime.sleep(e.retry_after_seconds or 1.0)except (ServerError, MemorySyncError):if i == attempts - 1:raisetime.sleep((2 ** i) + random.random())
Logging an error end-to-end
Every error has the request id; log it next to your own correlation id so support can find the call in seconds.
PYTHON
import logginglog = logging.getLogger(__name__)try:client.add(text="...")except MemorySyncError as e:log.error("memorysync call failed",extra={"memorysync_request_id": e.request_id,"memorysync_status": e.status_code,"memorysync_response": e.response,},)raise
Things to never do
Anti-patterns
Catching
Exception blindly hides bugs. Re-raising as a different type loses request_id. Swallowing AuthError just makes the next 1000 calls fail too. Each error class exists so you can take a different action.