Skip to content

Exceptions

All exceptions raised by the SDK inherit from SonnysError. The hierarchy is:

SonnysError
  APIError
    APIConnectionError
      APITimeoutError
    APIStatusError
      AuthError
      RateLimitError
      ValidationError
      NotFoundError
      ServerError
  BackOfficeError
    BackOfficeCredentialsError
    BackOfficeLoginError
    BackOfficeScrapeError

Catch SonnysError to handle any SDK error, or catch specific subclasses for fine-grained control:

from sonnys_data_client import SonnysClient, AuthError, RateLimitError, SonnysError

try:
    client.customers.list()
except AuthError:
    print("Invalid credentials")
except RateLimitError:
    print("Too many requests")
except SonnysError:
    print("Something else went wrong")

SonnysError

Bases: Exception

Base exception for all Sonny's Data Client errors.

APIError

APIError(message: str)

Bases: SonnysError

An error returned by the API.

Attributes:

Name Type Description
message

Human-readable error description.

APIConnectionError

APIConnectionError(message: str = 'Connection error.')

Bases: APIError

Failed to connect to the Sonny's Data API.

APITimeoutError

APITimeoutError(message: str = 'Request timed out.')

Bases: APIConnectionError

Request to the Sonny's Data API timed out.

APIStatusError

APIStatusError(
    message: str,
    *,
    status_code: int,
    body: dict | None = None,
    error_type: str | None = None,
)

Bases: APIError

API returned an error HTTP status.

Attributes:

Name Type Description
status_code

The HTTP status code returned by the API.

body

The parsed JSON error body, if available.

error_type

The Sonny's API error type string, if available.

AuthError

AuthError(
    message: str,
    *,
    status_code: int,
    body: dict | None = None,
    error_type: str | None = None,
)

Bases: APIStatusError

Authentication or authorization failed (HTTP 403).

Raised for invalid/missing API credentials or unauthorized site access.

RateLimitError

RateLimitError(
    message: str,
    *,
    status_code: int,
    body: dict | None = None,
    error_type: str | None = None,
)

Bases: APIStatusError

Rate limit exceeded (HTTP 429).

The client auto-retries with backoff, so this is only raised after retries are exhausted.

ValidationError

ValidationError(
    message: str,
    *,
    status_code: int,
    body: dict | None = None,
    error_type: str | None = None,
)

Bases: APIStatusError

Request validation failed (HTTP 400/422).

Check error_type and body for details on invalid parameters.

NotFoundError

NotFoundError(
    message: str,
    *,
    status_code: int,
    body: dict | None = None,
    error_type: str | None = None,
)

Bases: APIStatusError

Requested resource not found (HTTP 404).

ServerError

ServerError(
    message: str,
    *,
    status_code: int,
    body: dict | None = None,
    error_type: str | None = None,
)

Bases: APIStatusError

Sonny's API server error (HTTP 500+).

BackOfficeError

Bases: SonnysError

Base class for errors raised by the BackOffice web-UI scraper.

BackOfficeCredentialsError

Bases: BackOfficeError

BackOffice methods were called without credentials supplied at client construction. Construct the client with backoffice_username and backoffice_password to enable the BackOffice resource.

BackOfficeLoginError

Bases: BackOfficeError

Authentication with the BackOffice web UI failed.

Raised when the login form rejects the credentials (the server redirects back to /login) or when the login endpoint is unreachable.

BackOfficeScrapeError

Bases: BackOfficeError

The BackOffice report page did not match the expected structure.

Raised when required HTML elements (the period header, employee blocks, or the timesheet-total footer) are missing — usually a sign that the page layout has changed.