Error Envelope
JSON-API-inspired error format. Stable machine-readable codes. Source pointers for validation.
Shape
type ErrorResponse = {
errors: Error[]
}
type Error = {
code: string // machine-readable; stable identifier
title: string // human-readable summary
detail?: string // specific message for this instance
source?: {
pointer?: string // JSON Pointer to the field in the request body
parameter?: string // query string parameter name
header?: string // request header name
}
meta?: Record<string, unknown> // anything extra (e.g., row count, correlation_id)
} Common codes
| Code | HTTP | Meaning |
|---|---|---|
unauthorized | 401 | Token missing, expired, or unrecognized |
scope_missing | 401 | Token doesn't carry the required scope |
forbidden | 403 | Auth'd, but the action isn't allowed (resource-level) |
override_required | 403 | Endpoint requires X-Operator-Override flag |
bulk_override_required | 403 | Operation exceeds bulk threshold; include bulk in override |
not_found | 404 | Resource doesn't exist or not visible to the token |
idempotency_conflict | 409 | Same key + endpoint, different body |
cursor_invalid | 410 | Cursor's sort/filter signature no longer matches |
validation_failed | 422 | Request body doesn't satisfy schema |
cache_warming | 202 | Insight cache is computing; retry per Retry-After |
rate_limited | 429 | Request rate exceeded; see Retry-After and RateLimit-* headers |
internal_error | 500 | Unhandled server failure; correlation ID in meta.correlation_id |
Multiple errors per response
Validation failures return multiple errors entries — one per field. Other errors are typically single.
{
"errors": [
{
"code": "validation_failed",
"title": "Field is required",
"detail": "name must be present",
"source": { "pointer": "/data/attributes/name" }
},
{
"code": "validation_failed",
"title": "Invalid format",
"detail": "email must be a valid email address",
"source": { "pointer": "/data/attributes/email" }
}
]
} Correlation IDs on 5xx
Every 5xx response carries a meta.correlation_id matching gondor's request log. Forward it to support to trace a specific failed request.
{
"errors": [
{
"code": "internal_error",
"title": "Server error",
"detail": "Please contact support with the correlation_id",
"meta": { "correlation_id": "01H8XK3J5Z9M2P4Q6R8S0T2V4W" }
}
]
} Why machine-readable codes
The code field is the contract. title and detail are subject to copy changes; the code stays stable across versions. Switch on code in your handler, never the HTTP status alone (multiple codes share statuses — see unauthorized + scope_missing both at 401).