Skip to content

Errors

Every failure raises a subclass of TopolabError, so you never parse raw JSON.

Error When
AuthenticationError missing or invalid API key (401)
AddonRequiredError key lacks the add-on — .addon names it (403)
AccessDeniedError dataset not accessible to your organization (403)
InsufficientCreditsError not enough credits — .required / .available (402)
NotFoundError unknown dataset or collection (404)
ValidationError invalid request parameters (400/4xx)
QueryTimeoutError SQL query exceeded the server statement timeout (408)
RateLimitError rate limited — .retry_after, retried automatically (429)
ConfigurationError client misconfiguration (e.g. missing/invalid key or base URL)
ServerError upstream error (5xx), retried automatically
ConnectionError network failure / timeout after retries
from topolab import Client, AddonRequiredError

tl = Client(api_key="tlb_prod_...")
try:
    tl.dataset("nl-domino-poi").to_geojson()
except AddonRequiredError as e:
    print("Your key needs:", e.addon)

The error envelope

Every failure carries the same body, produced by the engine's global exception filter:

{ "code": 403, "message": "This endpoint requires the api-access add-on",
  "path": "/v1/dataset/{table}/files/geojson", "method": "GET",
  "time": "2026-09-08T23:42:15.819Z", "requestId": "25c2a6a1…" }

There is no statusCode field — the SDK maps errors from the HTTP status, never from a body field. request_id comes from the X-Request-Id header and falls back to the body's requestId; quote it in support requests.

Add-on requirements

A 403 whose message names an add-on becomes an AddonRequiredError, and .addon is the normalised hyphenated slug (api-access, gis-access, archived-data, high-value-data, sql-access). Both message shapes the API emits normalise to the same value:

Message .addon
This endpoint requires the api-access add-on api-access
Archive access requires the Archived Data add-on. Please upgrade to access historical data. archived-data

Any other 403 on a data route is an AccessDeniedError — the dataset is unknown to you, or not licensed.

Archives: 400 vs 404

An impossible month (2026-13, 2026-07-99, 2026-02-29) never reaches the network: archive() validates it as a calendar value and raises ValueError. The same value sent by hand answers 400. A 404 means no archive is available for a real month — including months outside your retention window and months that have not started, which are deliberately indistinguishable.

Retries

Transient failures (429, 500, 502, 503, 504) and network errors are retried with exponential backoff, honouring a Retry-After header or retryAfter body field when present. max_retries (default 3) is the number of retries after the first attempt.