Skip to main content
All errors use standard HTTP status codes plus a structured detail object. The body shape is consistent:
Every response except unhandled 500s carries X-Request-ID. You can also send your own X-Request-ID request header — the server echoes it and binds it to its log lines, which is the reliable way to correlate even the responses that lack the header.

Error code reference

Billing and rate limits

Both apply to every metered endpoint, and both are raised by the shared admission gate before any work is done — so a 402 or a 429 is never billed. A 402 body distinguishes its three causes so a client can route each one correctly instead of treating them all as “out of credits”: Every 402 also carries plan, used, included, limit, and resets_at, so the numbers reconcile against the dashboard. Every finite plan hard-stops and no tier carries overage — see Pricing. Authentication and account-route failures (401 auth_*, 403, 429 rate_limited) use the same detail shape — the full table lives on the Authentication page. Unhandled server exceptions return a plain 500 Internal Server Error (no structured detail body, and no X-Request-ID response header — the framework default, since the error bypasses the header middleware). The server-side log line still carries the request ID, so send your own X-Request-ID request header if you need to correlate a 500.

Worked examples

The validation examples below need a valid token — authentication runs before request validation, so an unauthenticated call returns 401 auth_missing rather than the 400s shown.

coord_out_of_bounds

no_fields_requested

fields_unknown

Common gotchas:
  • elevation_melevation (no unit suffix).
  • slopeslope_degrees (unit suffix required to disambiguate from aspect_degrees).
  • floodplainwithin_floodplain_polygon (full predicate name).
  • power_plantnearest_power_plant_name (or …_distance_m, …_primary_fuel, …).

fields_too_many

Pydantic validation errors (FastAPI default)

If the request body fails schema validation (e.g. missing lat, wrong type), FastAPI’s default 422 response shape applies:
These are caller bugs (malformed request, not a domain-level error) and should be caught in client-side serialization. The structured loc path tells you which field needs fixing.

What is NOT an error

  • Partial source failures in /v1/fetch are 200 OK with a populated partial_failures array. Failed sources never cause a non-200 response. This is the honesty pattern.
  • Low-confidence /v1/ask answers are 200 OK with confidence: "low". We still return the answer the synthesizer wrote; the confidence bucket tells the caller how much to trust it.
  • An imprecise /v1/geocode coordinate is 200 OK. Only a centroid-grade result is rejected as address_too_coarse; a street-interpolated one is returned and labelled range_interpolation, and it is the caller’s job to read accuracy_type.

Reporting issues

If you hit an unexplained 500, please include:
  • Your X-Request-ID request header value if you set one (plain 500s don’t echo it back, but the server log line has it).
  • The request body (sanitized).
  • Approximate timestamp (UTC) and endpoint.
We’ll find the corresponding log line in Fly logs.