Skip to content

Error Handling

Christian KASSE edited this page Apr 2, 2026 · 1 revision

Error Handling

Exception Hierarchy

All SDK exceptions inherit from EssabuError:

EssabuError (base)
  |-- AuthenticationError   (401)
  |-- AuthorizationError    (403)
  |-- NotFoundError         (404)
  |-- ConflictError         (409)
  |-- ValidationError       (422)
  |-- RateLimitError        (429)
  |-- ServerError           (5xx)

Importing Exceptions

from essabu.common.exceptions import (
    EssabuError,
    AuthenticationError,
    AuthorizationError,
    NotFoundError,
    ConflictError,
    ValidationError,
    RateLimitError,
    ServerError,
)

Exception Properties

EssabuError (Base)

Property Type Description
message str Human-readable error message
status_code `int None`
body dict Raw response body
headers dict Response headers

ValidationError

Property Type Description
errors list[dict] List of field-level errors

RateLimitError

Property Type Description
retry_after `float None`

Usage Examples

Catching Specific Errors

try:
    employee = client.hr.employees.retrieve("nonexistent-id")
except NotFoundError as e:
    print(f"Not found: {e.message}")
except ValidationError as e:
    print(f"Validation failed:")
    for err in e.errors:
        print(f"  - {err}")
except AuthenticationError:
    print("Invalid API key -- check your credentials")
except AuthorizationError:
    print("Insufficient permissions for this action")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except ServerError as e:
    print(f"Server error ({e.status_code}): {e.message}")
except EssabuError as e:
    print(f"Unexpected API error: {e.status_code} - {e.message}")

Catch-All Pattern

try:
    result = client.accounting.invoices.create(
        customer_id="cust-001",
        items=[{"description": "Service", "quantity": 1, "unit_price": 100}],
    )
except EssabuError as e:
    print(f"API error: {e}")
    # Log e.body for debugging

Handling Rate Limits

import time

def safe_request():
    try:
        return client.hr.employees.list()
    except RateLimitError as e:
        if e.retry_after:
            time.sleep(e.retry_after)
            return client.hr.employees.list()
        raise

Handling Validation Errors

try:
    client.hr.employees.create(email="not-an-email")
except ValidationError as e:
    for error in e.errors:
        field = error.get("field", "unknown")
        msg = error.get("message", "invalid")
        print(f"Field '{field}': {msg}")

Best Practices

  1. Catch specific exceptions first, then fall back to EssabuError
  2. Log the full exception (including body and headers) for debugging
  3. Handle rate limits gracefully by respecting retry_after
  4. Never expose API error details to end users in production
  5. Use the retry mechanism -- the SDK retries transient errors automatically

Clone this wiki locally