Qartas Error Reference

Error envelope

JSON endpoints return errors as:

{
  "status": "error",
  "error": {"code": "MACHINE_CODE", "message": "human text", "details": {"...": "..."}},
  "message": "human text"
}

Complete code catalog

Authentication — API key (all requests)

Code HTTP Meaning Handling
MISSING_TOKEN 401 No X-API-Key and no Authorization header on a credentialed endpoint. Send your key.
INVALID_API_KEY 401 Key unknown, malformed, or revoked. Check for truncation/whitespace; if the key was working before, it has been revoked — contact the operator. Do not retry unchanged.
API_KEY_EXPIRED 401 Key exists but is inactive or past its expires_at. Contact the operator for a replacement.
MAPS_AUTH_UNAVAILABLE 503 Server-side auth subsystem misconfigured/unavailable. Transient from your perspective — retry with backoff; report if persistent.

Authentication — tile family (/tiles, /style, /glyphs, /sprites)

Code HTTP Meaning Handling
AUTH_REQUIRED 401 Neither X-API-Key nor ?t= presented. Attach a credential.
INVALID_TOKEN 401 Tile token malformed or signature mismatch. Re-mint via POST /maps/v1/tile-token; pass it URL-unmodified.
TOKEN_EXPIRED 401 Tile token past its expiry (24 h default). Mint a new token. Build refresh at ~80% of lifetime (the SDK does).
TOKEN_NOT_KEY_BOUND 401 Token is valid but wasn't minted from an API key (or its binding is malformed). Mint the token with your API key.
API_KEY_REVOKED 401 The key this token was minted from is no longer active. Contact the operator. All that key's tokens are dead.

Rate limiting & quota

Code HTTP Meaning Handling
RATE_LIMIT_EXCEEDED 429 Per-minute limit hit (per-key on credentialed endpoints, per-IP on the tile family). Retry-After: <seconds left in window>. Back off for Retry-After, then retry. Add client-side throttling/debouncing if recurrent.
MAPS_QUOTA_EXCEEDED 429 Daily miss-quota exhausted for this key (bucket-specific: "gather" for JSON endpoints, "tiles" for staticmap). Retry-After: 3600. Resets at midnight UTC. If hit in normal operation, your plan is undersized — contact the operator.

Request validation (fix the request; never retry unchanged)

Code HTTP Endpoint(s) Meaning
VALIDATION_ERROR 400 any JSON-body endpoint Body failed binding: missing/empty required field, non-JSON body, or a required numeric field sent as 0 (zero coordinates are rejected). Message names the field.
SAME_POINT 400 /directions, /prefetch-directions Origin ≈ destination with no waypoints.
TOO_MANY_WAYPOINTS 400 /directions, /prefetch-directions More than 4 waypoints.
BAD_WAYPOINT 400 /directions, /prefetch-directions A waypoint is out of range, NaN/Inf, or (0,0).
ENRICH_MANEUVERS_UNSUPPORTED 400 /directions, /prefetch-directions enrich_maneuvers: true was sent — not available on this service; omit the flag (native maneuvers[] still appear when the routing tier returns them).
MISSING_ID 400 /place/{id} Empty place ID.
BAD_PLACE_ID 400 /place/{id} ID doesn't match any known place-ID shape (after g_/w_ prefix strip).
MISSING_COORDS 400 /place-photos lat/lng missing or non-numeric.

Service availability & upstream (transient — retry with backoff)

Code HTTP Retry-After Meaning
MAPS_UNAVAILABLE 503 The maps engine is not enabled on this server (also used by tile auth when the engine is down). Genuine outage/maintenance signal.
AUTOCOMPLETE_BACKPRESSURE / GEOCODE_BACKPRESSURE / PLACE_BACKPRESSURE 503 3 Gather pools momentarily saturated; the request was shed before doing work. Retry after the delay.
REVERSE_BACKPRESSURE 503 2 Same, reverse-geocode pool.
DIRECTIONS_BACKPRESSURE 503 5 Same, routing pool.
AUTOCOMPLETE_UNAVAILABLE / GEOCODE_UNAVAILABLE / REVERSE_UNAVAILABLE / PLACE_UNAVAILABLE 503 5 Every source tier failed for this lookup. Retry shortly.
AUTOCOMPLETE_DISABLED / GEOCODE_DISABLED / REVERSE_DISABLED / PLACE_DISABLED 503 Feature disabled server-side. Don't hot-retry; report if unexpected.
AUTOCOMPLETE_FAILED / GEOCODE_FAILED / REVERSE_FAILED / PLACE_FAILED 502 Unclassified upstream failure (catch-all). Retry with backoff.
DIRECTIONS_UNROUTABLE 422 No route exists between the coordinates (e.g. across an ocean, outside the routable region). Not transient — don't retry unchanged.
VECTOR_TILES_NOT_SUPPORTED 501 Vector tiles are not part of this product (deliberate). Never retry.
TILE_TOKEN_FAILED 500 Token minting failed server-side (misconfiguration). Sanitized body + request_id; report it.
REQUEST_TIMEOUT 504 The 30 s whole-request timeout fired. Retry; for directions prefer max_wait_ms so you get the degraded-200 instead. (Envelope note: no top-level message field on this one.)

Remember: /directions converts most engine failures into a degraded 200 (partial: true, source: "server_straight") rather than a 5xx — absence of an error does not mean you have a road route. Check partial on every directions response.

Non-error "empty" answers (HTTP 200 — do not treat as failures)

Signal Endpoint Meaning
predictions: [] + budget_expired: true autocomplete Not authoritative — still gathering. Retry shortly.
predictions: [] + budget_expired: false autocomplete Authoritative no-match.
matched: false geocode No match for the address.
source: "no_address" reverse Genuinely nothing at that coordinate.
photos: [] place-photos No photos exist there (common).
queued: false, reason: "prefetch_saturated" prefetch-directions Prefetch skipped (pool full) — harmless.

Bare-status errors on binary endpoints (no JSON body)

Status Endpoints Meaning Retry?
400 tiles, glyphs, staticmap Malformed path/params (bad z/x/y, unsupported format, path traversal, <2 staticmap points). No.
404 tiles, style, glyphs, sprites Asset doesn't exist (unknown style name, unbundled glyph range, origin tile miss). No.
502 tiles, staticmap Transient upstream failure / non-image origin body (tiles send Retry-After: 1). Yes, briefly deferred.
503 tiles Degraded tile on a prefetch request (X-Chaf-Prefetch), or service disabled. Yes, later.
504 tiles Origin fetch timed out (Retry-After: 1). Yes, briefly deferred.

Suggested retry policy

Class Policy
400 / 422 / 501 Never retry unchanged — fix the request (or, for 501, drop the feature).
401 Re-mint tile tokens on TOKEN_EXPIRED/INVALID_TOKEN; otherwise escalate (key problem), don't loop.
429 Wait exactly Retry-After, retry once, then surface to your own throttling.
503 with Retry-After Honor it (2–5 s), retry up to 2–3 times with jitter.
502 / 504 / other 503 Exponential backoff with jitter, small cap (e.g. 1 s, 2 s, 4 s).
500 Retry once after a few seconds; then report with the request_id.

This catalog was produced by enumerating every response.Error / AbortWithStatusJSON / bare-status call site in internal/api/*.go and the engine's tile error mapping (internal/engine/tiles.go, internal/api/tiles.go), then spot-checking representative cases live (SAME_POINT, TOO_MANY_WAYPOINTS, ENRICH_MANEUVERS_UNSUPPORTED, BAD_PLACE_ID, VALIDATION_ERROR, INVALID_API_KEY, MISSING_TOKEN, AUTH_REQUIRED, INVALID_TOKEN, RATE_LIMIT_EXCEEDED, VECTOR_TILES_NOT_SUPPORTED, post-revoke 401s) on 2026-07-31. Codes not individually triggered live (the 5xx family, backpressure/unavailable states, JWT-path codes) are verified from source only.

← Documentation