Error Handling
The PrairieCloud API uses RFC 7807 Problem Details for HTTP APIs for all error responses. This provides a consistent, machine-readable format across every endpoint.
Problem Details Format
Every error response has Content-Type: application/problem+json and this structure:
{
"type": "https://prairiecloud.io/errors/not-found",
"title": "Resource Not Found",
"status": 404,
"detail": "Variable 'median_age_foo' does not exist in the catalog",
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"instance": null,
"errors": null
}
| Field | Type | Description |
|---|---|---|
type | string | A URI identifying the error type. Stable and machine-readable. |
title | string | Short human-readable summary. Doesn't change between occurrences. |
status | integer | HTTP status code (mirrors the HTTP response status). |
detail | string | Human-readable explanation of this specific occurrence. |
request_id | string | UUID for this request — include this when contacting support. |
instance | string|null | URI identifying the specific occurrence (optional). |
errors | array|null | Structured validation errors; populated for 422 responses. |
Error Code Reference
HTTP 400 — Bad Request
The request was malformed or a parameter had an invalid value.
| Error Type URI | Meaning |
|---|---|
…/errors/validation-error | One or more query parameters failed validation |
…/errors/invalid-vintage | The vintage year is not supported |
…/errors/invalid-dataset | The dataset key is not recognized |
HTTP 401 — Unauthorized
Authentication failed.
| Error Type URI | Meaning |
|---|---|
…/errors/missing-api-key | No X-API-Key header or api_key query param provided |
…/errors/invalid-api-key | The key does not exist or has been revoked |
HTTP 404 — Not Found
A requested resource doesn't exist.
| Error Type URI | Meaning |
|---|---|
…/errors/not-found | Variable, geography, or resource not found |
…/errors/variable-not-found | The api_name doesn't exist in the catalog |
…/errors/geography-not-found | The geo key doesn't match any geography |
HTTP 422 — Unprocessable Entity
The request was syntactically valid but semantically invalid. The errors array contains field-level detail:
{
"type": "https://prairiecloud.io/errors/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "query → vintage: Input should be a valid integer",
"request_id": "...",
"errors": [
{
"field": "query → vintage",
"message": "Input should be a valid integer",
"type": "int_parsing"
}
]
}
HTTP 429 — Too Many Requests
Rate limit exceeded. The response includes your current plan, quota, and an upgrade URL:
{
"type": "https://prairiecloud.io/errors/rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "Monthly quota of 1,000 units exhausted for tier 'free'.",
"instance": "/v1/data",
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"limit_type": "monthly",
"plan": "free",
"quota": 1000,
"upgrade_url": "https://dashboard.prairiecloud.io/dashboard/billing/"
}
See Rate Limiting for full details on quotas, request cost, and retry strategy.
HTTP 403 — Terms of Service Acceptance Required
The authenticated user has not accepted the current version of the Terms of Service, and the grace period has expired. Visit dashboard.prairiecloud.io to review and accept the updated terms.
{
"type": "https://prairiecloud.io/errors/tos-acceptance-required",
"title": "Terms of Service Acceptance Required",
"status": 403,
"detail": "Updated Terms of Service must be accepted before using the API. Visit https://dashboard.prairiecloud.io to review and accept the updated terms."
}
HTTP 403 — Feature Requires Upgrade
Returned when a Free or Pioneer user attempts to access a Pro-tier feature (e.g., CSV export, wildcard geography).
| Error Type URI | Meaning |
|---|---|
…/errors/feature-requires-upgrade | The requested feature requires a higher-tier plan |
{
"type": "https://prairiecloud.io/errors/feature-requires-upgrade",
"title": "Feature Requires Upgrade",
"status": 403,
"detail": "CSV export requires a Pro plan or higher.",
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"upgrade_url": "https://dashboard.prairiecloud.io/dashboard/billing/"
}
The upgrade_url links directly to the billing page where the user can upgrade their plan. See Rate Limiting — Tier-Gated Features for the full list of gated features.
HTTP 500 — Internal Server Error
An unexpected error on our side. These are rare and automatically monitored. The request_id in the response is useful when reporting issues.
HTTP 503 — Service Unavailable
A downstream dependency (database, Redis, external service) is temporarily unavailable. Retry with backoff.
HTTP 503 — Feature Unavailable
Returned when a feature is temporarily disabled via a feature flag. This is distinct from a general service outage.
| Error Type URI | Meaning |
|---|---|
…/errors/feature-unavailable | The requested feature is temporarily disabled |
{
"type": "https://prairiecloud.io/errors/feature-unavailable",
"title": "Feature Unavailable",
"status": 503,
"detail": "CSV export is temporarily unavailable. Please try again later.",
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
This is a transient condition — retry with backoff. Unlike feature-requires-upgrade (403), this error applies to all tiers and indicates a temporary system-level disable, not a billing restriction.
Validation Error Detail (422)
For parameter validation errors, the errors array provides field-level context:
{
"type": "https://prairiecloud.io/errors/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "query → geo: Field required",
"request_id": "a1b2c3d4-...",
"errors": [
{
"field": "query → geo",
"message": "Field required",
"type": "missing"
}
]
}
Each error object contains field (the parameter path, e.g. query → geo), message (human-readable description), and type (the validation error type).
Common Mistakes and Fixes
Missing API Key
{
"status": 401,
"detail": "No API key provided. Pass your key in the X-API-Key header."
}
Fix: Add the X-API-Key header to every request.
# Wrong
curl "https://api.prairiecloud.io/v1/data?variables=..."
# Right
curl -H "X-API-Key: pck_live_..." \
"https://api.prairiecloud.io/v1/data?variables=..."
Invalid Geography Format
{
"status": 400,
"detail": "Invalid geo specifier 'tx'. Expected format: {type}:{fips}, e.g. 'state:48'."
}
Fix: Use the {type}:{fips} format with numeric FIPS codes, not state abbreviations.
# Wrong
?geo=tx
# Right
?geo=state:48
Missing Leading Zero in FIPS Code
{
"status": 404,
"detail": "Geography 'state:6' not found."
}
Fix: FIPS codes require leading zeros. California is 06, not 6.
# Wrong
?geo=state:6
# Right
?geo=state:06
Variable Name Typo
{
"status": 404,
"detail": "Variable 'median_household_income_2023' does not exist in the catalog."
}
Fix: Variable names (api_name) don't include the vintage year. Use the /v1/variables endpoint to browse and search the correct names.
curl -H "X-API-Key: YOUR_KEY" \
"https://api.prairiecloud.io/v1/variables?search=median+household"
Requesting an Unavailable Vintage
{
"status": 400,
"detail": "Vintage 2001 is not available. Supported vintages: 2009–2024 (acs5), 2005–2024 (acs1)."
}
Fix: Check which vintages are loaded using the variable detail endpoint, or use the default (latest) vintage by omitting the vintage parameter.
Handling Errors in Code
Always check the HTTP status code before parsing the response body. When the status is not 2xx, parse the body as a ProblemDetail object:
import requests
response = requests.get(
"https://api.prairiecloud.io/v1/data",
headers={"X-API-Key": api_key},
params={"variables": "income_median_household", "geo": "state:48"}
)
if not response.ok:
error = response.json()
print(f"Error {error['status']}: {error['detail']}")
print(f"Request ID: {error['request_id']}")
else:
data = response.json()
# process data...
Include the request_id in any bug reports or support requests — it allows us to look up the exact request in our logs.
Next Steps
- Rate Limiting — 429 errors, retry strategies, and quota management
- API Keys — Authentication errors and key management
- API Reference — Full endpoint documentation with response schemas