Errors¶
Failures are raised as typed conditions you can catch by class. Every class
inherits from topolab_error.
| Condition class | When |
|---|---|
topolab_authentication_error |
missing or invalid API key (401) |
topolab_insufficient_credits_error |
not enough credits — $required / $available (402) |
topolab_addon_required_error |
key lacks the add-on — $addon names it (403) |
topolab_access_denied_error |
dataset not accessible to your organization (403) |
topolab_not_found_error |
unknown dataset, collection, or archive month (404) |
topolab_query_timeout_error |
SQL query exceeded the server statement timeout (408) |
topolab_rate_limit_error |
rate limited — $retry_after, retried automatically (429) |
topolab_configuration_error |
client misconfiguration (missing key, invalid base URL) |
topolab_validation_error |
invalid request parameters (400/4xx), including ones caught client-side |
topolab_server_error |
upstream error (5xx), retried automatically |
ds <- tl_dataset(tl, "nl-domino-poi")
result <- tryCatch(
tl_geojson(ds),
topolab_addon_required_error = function(e) {
message("Your key needs: ", e$addon)
NULL
}
)
The error envelope¶
Every failure carries the same body, produced by the API'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 — code merely mirrors the HTTP status, so
the package maps conditions from the HTTP status and never from a body
field. Each condition carries:
| Field | Meaning |
|---|---|
$status |
HTTP status code |
$message |
Server message |
$request_id |
X-Request-Id header, falling back to the body's requestId |
Quote $request_id when reporting a problem.
Recognising an add-on requirement¶
Two message shapes carry an add-on requirement, and a 403 that matches neither is an access denial:
| 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 |
Add-on identifiers are hyphenated slugs (api-access, gis-access,
archived-data, high-value-data, sql-access). Both phrasings normalise to
the same slug, so you can branch on $addon directly:
tryCatch(
tl_archive(ds, "poi.zip"),
topolab_addon_required_error = function(e) {
if (identical(e$addon, "archived-data")) message("Archives need the Archived Data add-on.")
}
)
Failing fast, before the round trip¶
Some invalid arguments are rejected locally as a topolab_validation_error
rather than sent, which saves a round trip and — on metered routes — a credit:
- an archive
monththat is malformed or not a real calendar month ("2026-13","2026-07-99","2026-02-29"), - an unsupported bulk
formatontl_download()ortl_archive(), limit/offset/page_size/max_rowsoutside their allowed range.
Retries¶
Transient statuses (429, 500, 502, 503, 504) are retried with backoff
via httr2::req_retry, honouring a retryAfter body field when present.
max_retries (default 3) is the number of retries after the first attempt.
A 408 query timeout is not retried — rerun a cheaper query instead.