MemorySyncMemorySync
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

AttributeTypeMeaning
str(exc)strHuman-readable message — usually the server’s detail field.
status_codeint | NoneHTTP status; None for transport errors.
responseAnyParsed JSON body if the server returned one.
request_idstr | NoneServer-assigned request id, also in the X-Request-ID header.

Class-specific attributes

ClassExtra attributeUse it for
RateLimitErrorretry_after_secondsHow long to sleep before the next attempt. Comes from the server.
ValidationErrorInspect .response for the offending field; do not retry.
AuthErrorTreat as fatal; rotate or fix the key.
NotFoundErrorThe id you passed does not exist or is not visible to this key.
ServerErrorTemporary server-side problem. Safe to retry with backoff.
MemorySyncErrorNetwork 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 missing
except ValidationError as e:
raise # caller bug — surface it
except AuthError:
raise # ops issue — alert
except RateLimitError as e:
sleep(e.retry_after_seconds); retry()
except (ServerError, MemorySyncError) as e: # transient
backoff_and_retry(e)

A small retry helper you can paste

PYTHON
import time, random
from memorysync.errors import RateLimitError, ServerError, MemorySyncError
def with_retry(fn, *, attempts=3):
for i in range(attempts):
try:
return fn()
except RateLimitError as e:
if i == attempts - 1:
raise
time.sleep(e.retry_after_seconds or 1.0)
except (ServerError, MemorySyncError):
if i == attempts - 1:
raise
time.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 logging
log = 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.