Skip to content

Errors

The exceptions the Python SDK raises, which ones to handle, and how the SDK retries.

Catch the right exception

Every exception the SDK raises derives from SweatStackError. You never need to import httpx.

SweatStackError
├── SweatStackConnectionError      no response: DNS failure, refused connection, timeout
├── SweatStackTokenRefreshError    the access token expired and couldn't be refreshed
└── SweatStackAPIError             the API answered with an error status
    ├── SweatStackAuthError        401 or 403
    ├── SweatStackNotFoundError    404
    ├── SweatStackRateLimitError   429
    ├── SweatStackBadRequestError  any other 4xx
    └── SweatStackServerError      5xx

A SweatStackAPIError has status_code, url, method, request_id and body. SweatStackRateLimitError also has retry_after, in seconds, when the API sent one.

from sweatstack import Client, SweatStackAPIError, SweatStackNotFoundError

client = Client()
try:
    activity = client.activities.retrieve("act_123")
except SweatStackNotFoundError:
    activity = None
except SweatStackAPIError as error:
    print(error.status_code, error.request_id, error.body)
    raise

Include the request_id when you contact support about a failed request.

Know what each error means

Exception What to do
SweatStackAuthError (401) The token is missing or invalid. Sign in again.
SweatStackAuthError (403) The token is valid but lacks a scope, or is the wrong kind: app metadata needs an app's access token, not a personal API key.
SweatStackNotFoundError The ID doesn't exist, or you have no access to it.
SweatStackBadRequestError The request is invalid. body has the API's explanation. Fix the request; retrying won't help.
SweatStackRateLimitError Wait retry_after seconds. The SDK already retried; see below.
SweatStackServerError A server-side error. The SDK already retried; try again later.
SweatStackConnectionError No answer from the API. The SDK already retried; check the network.
SweatStackTokenRefreshError The refresh token is missing or expired. Sign in again with client.authenticate(force=True).

Retries and timeouts

The SDK retries a request after a connection error, a timeout, or a 408, 429, 500, 502, 503 or 504 response. It retries only GET, PUT and DELETE requests, because sending those twice has the same effect as sending them once. It never retries a POST: the API has no idempotency keys, so a retried create could create twice.

  • Retries per request: max_retries, default 2.
  • Wait between attempts: 0.5 s, then 1 s, then 2 s, with ±25 % random jitter, at most 8 s.
  • If the API sends Retry-After, the SDK waits that long instead. If Retry-After is longer than 60 s, the SDK raises SweatStackRateLimitError without waiting.
  • Total waiting per request: at most 30 s. After that, the SDK raises the last error.
  • A DELETE that returns 404 after a retry counts as a success: the first attempt deleted the record and its response was lost.

Each request waits at most timeout seconds, default 60, to connect and for each read. Streams, like activities.watch_backfill_status(), have no read timeout.

from sweatstack import Client

batch = Client(timeout=120.0, max_retries=4)   # a long batch job
web = Client(max_retries=0)                    # inside a web request: fail fast

Inside a web request, set max_retries=0 or a short timeout. The user waits for every retry.

To see the retries, enable debug logging for the sweatstack logger. Each retry logs the method, the path, the status and the request ID.

import logging

logging.basicConfig()  # a handler, so debug messages are printed
logging.getLogger("sweatstack").setLevel(logging.DEBUG)