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

Agent setup errors

The HTTP onboarding endpoints use these codes. Never include an API key in an error report.

Dollar billing and rate limits

Lookup and Resolve are retired. Their former resolve_* errors no longer describe active request handling; authenticated calls now return 410 endpoint_retired. Follow the migration guide. A completed result is normally saved for replay within seconds of the response. Until it is saved, a same-key retry or GET /v1/operations/{operation_id} returns 409 operation_in_progress with Retry-After. If it is still unsaved two minutes after the charge, the answer is a terminal 410 result_not_retained:
Paid error bodies include operation_id where one has been assigned. HTTP headers also expose X-Operation-Id. Free Fetch and Geocode do not consult the wallet. Paid results and replay delivery require fresh authorization; see Authentication for terms and credential errors.

Dataset availability

Dataset permission is separate from account access and accepted terms. These errors apply to Enrich, Search, Ask, Sites and their saved results in REST and hosted MCP. They do not disable free Fetch, Geocode or driving-only operations. Responses use Cache-Control: private, no-store. A withdrawal can make an unexpired saved result or Site unavailable. Reactivation does not restore old withdrawn results. Ordinary refreshes preserve access to saved results under the same permission epoch, subject to retention and account authorization, but invalidate Search continuation cursors. During streaming, a terminal error frame replaces the final answer; discard partial text. If a permission check interrupts source work before a complete result exists, the operation ends as operation_failed; start new work only after availability is restored. If work completed before a temporary permission outage, retry the same key to recover its saved result. A delivery refusal does not itself reverse an earlier settled charge or resolve an unknown payment outcome.

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_m → elevation (no unit suffix).
  • slope → slope_degrees (unit suffix required to disambiguate from aspect_degrees).
  • floodplain → within_floodplain_polygon (full predicate name).
  • power_plant → nearest_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. POST /v1/search returns HTTP 422 with search_invalid_request for malformed request shapes, search_invalid_filter for unsupported fields or typed conditions, and search_limit_exceeded for result counts above the supported maximum. These errors include issues with paths and correction hints, docs_url, and request_id. An invalid, expired, or request-mismatched cursor is search_invalid_request; restart without the cursor or resend the original filters, fields and enrich value. These errors are not retryable without correcting the request. The optional enrich flag must be a JSON boolean: null, strings and numbers return 422 search_invalid_request. The filters list must include a positive state or state2 selection: eq with one two-letter code, or in with a nonempty list of codes for the 50 US states or DC. Missing state, invalid codes, an empty state list, or only negative ne state predicates return 422 search_invalid_request. County and acreage are optional; a county name, FIPS code or geometry filter does not replace the state selection. 429 search_busy, 503 search_unavailable, and 504 search_deadline_exceeded are retryable and carry Retry-After: 3. Account rate limiting can specify another delay. A deployment without the API token signing secret returns 503 search_unavailable before candidate work; /readyz reports search_cursor_key_unconfigured. A 200 response can be limited or partial; inspect completion_reason and available fields or compact enriched_fields. Missing or null outputs do not establish a negative finding; full enrichment omits failed fields from its public map. Failed enrichment retains the match and makes the response partial; timeout failures use completion_reason: "timeout". Counts and processing diagnostics remain internal. See Search for the complete contract.

Enrich

POST /v1/enrich and mireye_enrich share the same request and result contract. Supply exactly one locator: address or both lat and lng. Invalid shapes, empty fields, and unknown presets return 422. Unknown individual field IDs return 400 fields_unknown; use the Enrich field reference. Enrich has no 50-field cap. Omitting both fields and preset requests all Enrich fields, so select a small set when correcting or retrying a request. Address inputs can return the shared Geocode errors above. Account rate limits return 429 rate_limited; worker capacity returns 429 fetch_busy. Respect Retry-After (2 seconds for fetch_busy, the response’s delay for account limits). HTTP 200 is not proof that a parcel was matched or every field succeeded. Inspect parcel_match.status: ambiguous, no_match, and unavailable return an empty fields map. A matched parcel can also return fields: {}: failed fields and most null-valued fields are omitted. Standalone Enrich exposes neither field statuses nor partial_failures, error, or retryable. Retained nulls come from a temporary allowlist and can still represent missing source attributes. Neither an omitted field nor a retained null proves absence, or tells you that a retry will help. Inline Search enrichment retains its field statuses and failure details. See Enrich.