Skip to main content

Error Handling

The SDK defines a hierarchy of exceptions for different error conditions.

Exception Hierarchy

StatehouseError
├── TransactionError
├── NotFoundError
└── ConnectionError

StatehouseError

Base exception for all SDK errors.

from statehouse import StatehouseError

try:
result = client.get_state(agent_id="agent", key="key")
except StatehouseError as e:
print(f"Statehouse error: {e}")

TransactionError

Raised for transaction lifecycle errors.

from statehouse import TransactionError

try:
with client.begin_transaction() as tx:
tx.write(agent_id="agent", key="key", value={"x": 1})
tx.commit()
tx.commit() # Raises TransactionError
except TransactionError as e:
print(f"Transaction error: {e}")

Common causes:

  • Attempting to write after commit
  • Attempting to commit after abort
  • Transaction timeout
  • Server rejected the transaction

NotFoundError

Raised when a requested resource doesn't exist.

from statehouse import NotFoundError

try:
result = client.get_state_at_version(
agent_id="agent",
key="key",
version=999,
)
except NotFoundError:
print("Version not found")

ConnectionError

Raised when the client cannot connect to the daemon.

from statehouse import ConnectionError

try:
client = Statehouse(url="localhost:99999")
client.health()
except ConnectionError as e:
print(f"Cannot connect: {e}")

Note: This is statehouse.ConnectionError, not the built-in ConnectionError.

Best Practices

Catch Specific Exceptions

from statehouse import (
StatehouseError,
TransactionError,
NotFoundError,
ConnectionError,
)

try:
with client.begin_transaction() as tx:
tx.write(agent_id="agent", key="key", value={"x": 1})
except ConnectionError:
# Handle connection issues (retry, failover)
pass
except TransactionError:
# Handle transaction failures (retry, log)
pass
except StatehouseError:
# Handle other errors
pass

Retry Logic

import time
from statehouse import ConnectionError, TransactionError

def write_with_retry(client, agent_id, key, value, max_retries=3):
for attempt in range(max_retries):
try:
with client.begin_transaction() as tx:
tx.write(agent_id=agent_id, key=key, value=value)
return
except (ConnectionError, TransactionError) as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt) # Exponential backoff

Logging Errors

import logging
from statehouse import StatehouseError

logger = logging.getLogger(__name__)

try:
result = client.get_state(agent_id="agent", key="key")
except StatehouseError as e:
logger.error(f"Statehouse operation failed: {e}", exc_info=True)
raise

gRPC Error Mapping

The SDK maps gRPC status codes to Python exceptions:

gRPC StatusPython Exception
UNAVAILABLEConnectionError
NOT_FOUNDNotFoundError
ABORTEDTransactionError
DEADLINE_EXCEEDEDTransactionError
OtherStatehouseError