Skip to content

Errors

Every failure throws 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 a SQL query exceeded the server statement timeout (408)
RateLimitError rate limited — .retryAfter, retried automatically (429)
ConfigurationError client misconfiguration (missing key, invalid base URL)
ServerError upstream error (5xx), retried automatically
ConnectionError network failure after retries
TimeoutError request exceeded the client timeout (subclass of ConnectionError)
import { Client, AddonRequiredError } from "@topolab/sdk";

const tl = new Client({ apiKey: "tlb_prod_..." });
try {
  await tl.dataset("nl-domino-poi").toGeoJSON();
} catch (e) {
  if (e instanceof AddonRequiredError) console.log("Your key needs:", e.addon);
}

The error envelope

Every failure shares one envelope, 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 numeric status is code, and it always equals the HTTP status. The SDK branches on the HTTP status, never on a body field. .requestId is taken from the X-Request-Id header, falling back to the envelope's requestId; quote it in support requests.

Recognising an add-on requirement

Add-on identifiers are hyphenated slugs — api-access, gis-access, archived-data, high-value-data, sql-access. Two message shapes carry a requirement, and both normalise to the same slug on .addon:

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

A 403 matching neither is an access denial (AccessDeniedError) — the dataset is unknown to you, or your organization has no licence for it.

Archives: 400 vs 404

A malformed or impossible month (2026-13, 2026-07-99) is a 400 (ValidationError); downloadArchive normally catches those client-side. A real month with no archive available is a 404 (NotFoundError) — as are months outside your retention window and months that have not started, which the API deliberately does not distinguish, so a response never reveals an archive you cannot access.

Retries

Transient statuses (429, 500, 502, 503, 504) and network errors are retried with exponential backoff, honouring Retry-After / retryAfter when present. maxRetries (default 3) is the number of retries after the first attempt.