Skip to content

Error catalog

This content is not available in your language yet.

Every error looks the same. Branch on error.type, never on error.message: the type is a stable contract, the message is English prose and may change. The doc_url in every error body points at the matching section of this page (#<type>), so an integrator can paste it straight from a log.

{
"error": {
"type": "insufficient_data",
"message": "No SAR scenes in the requested window",
"detail": { "window": ["2026-07-10", "2026-07-20"], "scenes_found": 0 },
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#insufficient_data"
}
}

request_id is on every response, success or failure, in the X-Request-Id header. Quote it in support requests - without it we cannot trace anything.

Retry means the same request may succeed later without any change on your side. Everything else needs a fix in the request, the key or the plan. detail is always a JSON object (possibly empty), never null.

/v1/openapi.json declares, for every operation, only the error statuses that operation can really return, all with the same ErrorEnvelope schema; each status description lists the error.type values possible there, and error.type is an enum of this catalog - a client generated from the document parses errors without any hand-written special case and sees at a glance which types it has to branch on. The four 422 types that mean “no honest number” also carry the X-Agrovisio-Not-Billable header, so a metered call that ends in one of them can be matched to the missing usage charge.

This catalog is generated from publicapi/errors.py (34 types, last sync 2026-11-04). The same list is exposed as x-agrovisio-error-catalog in /v1/openapi.json, so an SDK can assert it is complete.

error.type HTTP Retry
validation_error 400 no
geometry_invalid 400 no
geometry_invalid_type 400 no
geometry_too_small 400 no
geometry_too_large 400 no
geometry_too_complex 400 no
geometry_out_of_range 400 no
geometry_unsupported_region 400 no
date_range_invalid 400 no
bbox_too_large 400 no
crop_required 400 no
idempotency_key_required 400 no
authentication_failed 401 no
key_revoked 401 no
key_expired 401 no
payment_required 402 no
insufficient_scope 403 no
plan_does_not_include 403 no
ip_not_allowed 403 no
not_found 404 no
cadastre_not_found 404 no
method_not_allowed 405 no
idempotency_conflict 409 no
quota_exceeded_for_plan 409 no
definition_published 409 no
insufficient_data 422 yes
insufficient_resolution 422 no
baseline_not_ready 422 yes
vegetation_masked 422 yes
rate_limited 429 yes
parcel_quota_exceeded 429 no
internal_error 500 yes
upstream_unavailable 502 yes
service_unavailable 503 yes

The request itself is wrong. Fix it before retrying.

HTTP 400 - retry: no, change the request, key or plan first

Cause. A field is missing or has the wrong type.

Fix. Read detail.fields: it names every rejected field and the reason.

Variant - validation_error with detail.fields[].type: country_mismatch. The declared country is not where the geometry lies (detail.detected names the derived country). Omit country to derive it from the geometry, or fix the swapped field.

{
"error": {
"type": "validation_error",
"message": "Request validation failed",
"detail": {
"fields": [
{
"field": "event_date",
"reason": "Input should be a valid date",
"type": "date_parsing"
}
]
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#validation_error"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. Self intersecting or otherwise broken polygon that ST_MakeValid could not repair (detail.reason carries the PostGIS reason). A polygon that ST_MakeValid can repair is accepted, and the repair is reported in warnings with the resulting area_ha.

Fix. Run the geometry through a repair step (PostGIS ST_MakeValid, shapely buffer(0)) or re-export it from your GIS.

{
"error": {
"type": "geometry_invalid",
"message": "Geometry is not valid and could not be repaired",
"detail": {
"reason": "Self-intersection at or near point 24.0012 55.0021"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#geometry_invalid"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. Geometry is a Point, LineString or GeometryCollection.

Fix. Send a Polygon or MultiPolygon. Features and FeatureCollections are accepted and flattened.

{
"error": {
"type": "geometry_invalid_type",
"message": "Geometry must be a Polygon or MultiPolygon",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#geometry_invalid_type"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. Parcel is below the minimum area the optical sensor can resolve.

Fix. Merge adjacent fields, or accept that this parcel cannot be monitored.

{
"error": {
"type": "geometry_too_small",
"message": "Geometry is below the minimum parcel area",
"detail": {
"area_ha": 0.31,
"min_area_ha": 0.5
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#geometry_too_small"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. A single parcel above the area limit (detail.max_area_ha, currently 5 000 ha; detail.area_ha is what we measured) is almost always several fields in one polygon.

Fix. Split it into real field boundaries; anomalies averaged over thousands of hectares mean nothing.

{
"error": {
"type": "geometry_too_large",
"message": "Geometry exceeds the maximum parcel area",
"detail": {
"area_ha": 6120.4,
"max_area_ha": 5000
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#geometry_too_large"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. Too many vertices - usually an unsimplified export.

Fix. Simplify to about 1 m tolerance before sending; the area changes by less than 0.1 %.

{
"error": {
"type": "geometry_too_complex",
"message": "Geometry has too many vertices",
"detail": {
"vertices": 12840,
"max_vertices": 10000
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#geometry_too_complex"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. Coordinates are not in EPSG:4326 (often swapped lat/lon, or a national grid).

Fix. Reproject to WGS84 and send lon, lat order.

{
"error": {
"type": "geometry_out_of_range",
"message": "Coordinates are outside the EPSG:4326 range",
"detail": {
"lon": 6180422.1,
"lat": 55.7
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#geometry_out_of_range"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. The parcel is outside the countries we serve (detail.bbox is the extent we derived).

Fix. detail.supported lists the ISO country codes we serve; contact sales for new regions.

{
"error": {
"type": "geometry_unsupported_region",
"message": "Geometry is outside the supported countries",
"detail": {
"bbox": [
2.1,
48.6,
2.4,
48.9
],
"supported": [
"LT",
"LV",
"PL"
]
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#geometry_unsupported_region"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. from is after to, the window is empty, it exceeds the endpoint maximum, to is in the future on weather history (detail.reason: to_in_future), or a damage event_date is so recent that the 14 day post-event window has not closed (detail.reason: post_window_open).

Fix. Check detail.max_days and split long windows into several requests; for to_in_future end the window today and use the forecast endpoint for future days; for post_window_open order again on detail.available_from.

{
"error": {
"type": "date_range_invalid",
"message": "Invalid date range",
"detail": {
"days": 2190,
"max_days": 1826
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#date_range_invalid"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. The bbox filter covers more area than a single listing may scan.

Fix. Narrow the bbox or page through parcels with cursor.

{
"error": {
"type": "bbox_too_large",
"message": "Bounding box is too large",
"detail": {
"area_km2": 41200.5,
"max_km2": 10000
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#bbox_too_large"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. The model needs the crop to pick phenology and yield curves.

Fix. Set crop_hint on the parcel or pass crop on the request.

{
"error": {
"type": "crop_required",
"message": "A crop must be supplied for this endpoint",
"detail": {
"ndvi_integral": 71.2,
"pct_of_baseline": 94.1
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#crop_required"
}
}

HTTP 400 - retry: no, change the request, key or plan first

Cause. Every POST must carry Idempotency-Key.

Fix. Send a UUID v4 per logical operation and reuse it on retries.

{
"error": {
"type": "idempotency_key_required",
"message": "The Idempotency-Key header is required for POST requests",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#idempotency_key_required"
}
}

The key is missing, malformed or no longer valid.

HTTP 401 - retry: no, change the request, key or plan first

Cause. Missing, malformed or unknown key.

Fix. Send Authorization: Bearer sk_live_.... Keys are shown once - if lost, rotate.

{
"error": {
"type": "authentication_failed",
"message": "Missing or invalid API key",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#authentication_failed"
}
}

HTTP 401 - retry: no, change the request, key or plan first

Cause. The key was revoked in the portal.

Fix. Use a current key.

{
"error": {
"type": "key_revoked",
"message": "This API key has been revoked",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#key_revoked"
}
}

HTTP 401 - retry: no, change the request, key or plan first

Cause. The key passed its expiry date.

Fix. Issue a new key in the portal.

{
"error": {
"type": "key_expired",
"message": "This API key has expired",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#key_expired"
}
}

The account is suspended; GET /v1/account still answers.

HTTP 402 - retry: no, change the request, key or plan first

Cause. The account is suspended for an overdue invoice (14 days overdue; after 45 days it is closed and GET /v1/account answers 402 too). detail.status says which.

Fix. Settle the invoice; access resumes automatically.

{
"error": {
"type": "payment_required",
"message": "Account suspended due to an overdue payment",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#payment_required"
}
}

The key is valid but may not do this.

HTTP 403 - retry: no, change the request, key or plan first

Cause. The key is missing the scope this endpoint requires.

Fix. detail.required_scope names it. Issue a key with that scope.

{
"error": {
"type": "insufficient_scope",
"message": "The API key does not have the required scope",
"detail": {
"required_scope": "damage:write"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#insufficient_scope"
}
}

HTTP 403 - retry: no, change the request, key or plan first

Cause. The product is not in your plan.

Fix. detail.product names it. Upgrade the plan or drop the call.

{
"error": {
"type": "plan_does_not_include",
"message": "Your plan does not include this product",
"detail": {
"product": "risk"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#plan_does_not_include"
}
}

HTTP 403 - retry: no, change the request, key or plan first

Cause. The caller IP is not on the key allowlist. detail.ip is the address our edge saw on the TCP connection; X-Forwarded-For / X-Real-IP sent by the caller are ignored.

Fix. Add the egress IP or CIDR to the key in the portal.

{
"error": {
"type": "ip_not_allowed",
"message": "This IP address is not on the key allowlist",
"detail": {
"ip": "203.0.113.7"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#ip_not_allowed"
}
}

Unknown id, or a resource that belongs to another client (never a 403).

HTTP 404 - retry: no, change the request, key or plan first

Cause. Unknown id, or a resource that belongs to another client.

Fix. We answer 404 rather than 403 on purpose: a 403 would confirm the id exists.

{
"error": {
"type": "not_found",
"message": "Resource not found",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#not_found"
}
}

HTTP 404 - retry: no, change the request, key or plan first

Cause. The national registry has no parcel with that number.

Fix. Check the number format in detail.source, or send a geometry instead.

{
"error": {
"type": "cadastre_not_found",
"message": "Cadastral parcel not found",
"detail": {
"source": "LT LPIS",
"cadastral_no": "000467-3875"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#cadastre_not_found"
}
}

The path exists, but not for this HTTP method; the Allow header lists the methods it supports.

HTTP 405 - retry: no, change the request, key or plan first

Cause. The path exists, but not for this HTTP method (for example DELETE /v1/account).

Fix. The Allow header lists the methods the path supports; check the endpoint reference.

{
"error": {
"type": "method_not_allowed",
"message": "This method is not supported on this resource",
"detail": {
"method": "DELETE",
"path": "/v1/account"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#method_not_allowed"
}
}

The request contradicts stored state.

HTTP 409 - retry: no, change the request, key or plan first

Cause. The same Idempotency-Key was reused with a different body, or (detail.state: "in_progress") the original request with this key is still running.

Fix. Use a new key for a new operation; reuse it only for retries of the same one. For in_progress, wait for the Retry-After header (at most 120 s) and retry: you then get the stored result, or the key is free again if the original request never finished.

{
"error": {
"type": "idempotency_conflict",
"message": "The Idempotency-Key was reused with a different payload",
"detail": {
"idempotency_key": "6f1c2f7e-1f0e-4a0a-9a8e-1b2c3d4e5f60",
"state": "in_progress"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#idempotency_conflict"
}
}

HTTP 409 - retry: no, change the request, key or plan first

Cause. A plan change would leave you above the target plan quota.

Fix. Delete parcels first, or pick a bigger plan.

{
"error": {
"type": "quota_exceeded_for_plan",
"message": "Current usage exceeds the quota of the target plan",
"detail": {
"parcels_peak": 1450,
"target_plan": "starter",
"target_quota": 1000
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#quota_exceeded_for_plan"
}
}

HTTP 409 - retry: no, change the request, key or plan first

Cause. A published index definition is frozen - it backs signed contracts.

Fix. Create a new definition; it records supersedes automatically.

{
"error": {
"type": "definition_published",
"message": "A published index definition cannot be modified",
"detail": {
"definition_id": "idx_7A1MNPQRSTVWXYZ01234",
"published_at": "2026-03-01T09:12:00Z"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#definition_published"
}
}

The data does not support a result. Never billed; see below.

HTTP 422 - retry: yes, the same request may succeed later

Cause. No usable scenes in the window (cloud, no overpass, too few valid pixels), or a weather provider rejected the request itself (detail.reason: provider_rejected_request, detail.provider_status).

Fix. Widen the window or retry later. We never interpolate a value to hide a gap.

{
"error": {
"type": "insufficient_data",
"message": "Not enough data to produce a result",
"detail": {
"window": [
"2026-07-10",
"2026-07-20"
],
"scenes_found": 0
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#insufficient_data"
}
}

HTTP 422 - retry: no, change the request, key or plan first

Cause. The parcel is smaller than the sensor can resolve (Sentinel-3 needs >= 5 ha).

Fix. Use an S1 or S2 based product for this parcel.

{
"error": {
"type": "insufficient_resolution",
"message": "Parcel is too small for the sensor resolution",
"detail": {
"area_ha": 1.68,
"min_area_ha": 5,
"sensor": "sentinel-3-slstr"
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#insufficient_resolution"
}
}

HTTP 422 - retry: yes, the same request may succeed later

Cause. The historical baseline is still being built for this parcel.

Fix. Poll GET /v1/parcels/{id} for data_status.baseline_ready, subscribe to parcel.data_ready, or pass baseline=false to get the raw series now.

{
"error": {
"type": "baseline_not_ready",
"message": "Baseline backfill is not finished for this parcel",
"detail": {
"parcel_id": "prc_DXYN783DF81DPM9RMVHT",
"data_status": {
"s2_history_months": 0,
"baseline_ready": false
}
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#baseline_not_ready"
}
}

HTTP 422 - retry: yes, the same request may succeed later

Cause. Soil moisture cannot be read through a closed canopy.

Fix. Use the thermal water stress product during the growing season.

{
"error": {
"type": "vegetation_masked",
"message": "Soil signal is masked by vegetation",
"detail": {
"ndvi_threshold": 0.45,
"dates_masked": 6,
"dates_total": 6
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#vegetation_masked"
}
}

A speed limit (rate_limited) or a volume limit (parcel_quota_exceeded).

HTTP 429 - retry: yes, the same request may succeed later

Cause. The pool limit was hit. X-RateLimit-Pool says which one.

Fix. Back off until X-RateLimit-Reset, then retry. Batch endpoints exist for volume.

{
"error": {
"type": "rate_limited",
"message": "Rate limit exceeded",
"detail": {
"pool": "expensive",
"limit": 2,
"window_seconds": 60
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#rate_limited"
}
}

HTTP 429 - retry: no, change the request, key or plan first

Cause. The plan parcel quota (or the sandbox allowance) is exhausted.

Fix. Delete parcels, upgrade the plan, or - in sandbox - use the shared demo parcels.

{
"error": {
"type": "parcel_quota_exceeded",
"message": "Parcel quota for the current plan is exhausted",
"detail": {
"plan": "sandbox",
"quota": 10,
"active": 10,
"requested": 1
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#parcel_quota_exceeded"
}
}

Our fault, or a data provider is down. Retry with backoff.

HTTP 500 - retry: yes, the same request may succeed later

Cause. Our fault.

Fix. Retry with backoff; if it persists, send us request_id from the response.

{
"error": {
"type": "internal_error",
"message": "Internal error",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#internal_error"
}
}

HTTP 502 - retry: yes, the same request may succeed later

Cause. A data provider (Copernicus, a national registry, the weather archive) is down or timed out.

Fix. detail.provider names the satellite or weather provider (weather adds a short detail.reason such as timeout or provider_http_503); a cadastral registry is named in detail.source (registru_centras_lt, kadastra_lv, gugik_uldk_pl, the same id as source in a 200 lookup) with detail.reason registry_not_integrated (not connected yet) or registry_unavailable (down or timed out). Retry with backoff; the request is safe to repeat.

{
"error": {
"type": "upstream_unavailable",
"message": "An upstream data provider is unavailable",
"detail": {
"provider": "Copernicus Data Space Ecosystem",
"window": [
"2026-07-01",
"2026-07-31"
]
},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#upstream_unavailable"
}
}

HTTP 503 - retry: yes, the same request may succeed later

Cause. Maintenance or overload.

Fix. Retry after the Retry-After header.

{
"error": {
"type": "service_unavailable",
"message": "Service temporarily unavailable",
"detail": {},
"request_id": "req_5D2F9A1BCKMN",
"doc_url": "https://docs.agrovisio.ai/errors#service_unavailable"
}
}

validation_error carries detail.fields, one entry per rejected input:

{ "fields": [ { "field": "limit", "reason": "out of range" } ] }

field is the plain parameter name, whatever its location (query, path, header or body): limit, url, geometry.coordinates.0. A body that is not valid JSON at all is reported as a single entry with field: "body"; the parser position is in reason. A malformed cursor is reported as field: "cursor" with a fixed reason - always pass next_cursor exactly as the previous page returned it.

Authentication comes first: a request without a valid key gets 401 even when its body is unreadable, and the call counts against your rate limit only after the key was accepted.

429 rate_limited is a speed limit, 429 parcel_quota_exceeded is a volume limit. They are different problems:

  • rate limit - wait until X-RateLimit-Reset (epoch seconds) and retry. The pool that ran out is in X-RateLimit-Pool: standard, write or expensive. If the response also carries X-RateLimit-Burst-Limit, it was the per-second burst limit, not the minute window: X-RateLimit-Remaining still shows the minute budget, and Retry-After (usually 1) is the wait.
  • parcel quota - the billing unit is the monthly peak of active parcels, so deleting a parcel frees the quota but does not lower the peak for the period that already used it.

insufficient_data, baseline_not_ready, insufficient_resolution and vegetation_masked all mean the same thing: we have no honest number for you. In an insurance or credit decision a wrong number costs far more than a missing one, so we never interpolate silently. When a result is partially available the value is null with a reason next to it instead.

Calls that end in one of these states are not billed: the response carries X-Agrovisio-Not-Billable.