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. IfRetry-Afteris longer than 60 s, the SDK raisesSweatStackRateLimitErrorwithout waiting. - Total waiting per request: at most 30 s. After that, the SDK raises the last error.
- A
DELETEthat 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)