Errors
Every error uses the same envelope:
{ "error": { "code": "…", "message": "…" } }
code is a stable machine-readable string; message is a human-readable explanation. Some errors add fields (e.g. 429 adds retryAfterSec and scope). Guardian Logs never reveals whether another org, app, token, or resource exists.
Status codes
| Status | When | Typical code |
|---|---|---|
200 | Success (read endpoints). | — |
202 | Ingest accepted — inspect results[] for per-event outcome. | — |
400 | Invalid input or filter value. | malformed_json, empty, invalid_request |
401 | Missing / malformed / unknown / revoked / expired credential, or wrong credential type. Uniform. | unauthorized |
403 | Ingest: source disabled. Read: valid key missing the required scope. | source_disabled, forbidden |
404 | Resource not found (a cross-tenant id is indistinguishable from a nonexistent one). | not_found |
413 | Ingest payload too large (body > 1 MB, or > 500 events). | payload_too_large, batch_too_large |
429 | Rate limit exceeded. | rate_limited |
500 | Unexpected server error. | — |
503 is returned only by the public GET /api/health probe when the database is unreachable.
By surface
Read API (gl_api_…)
| Status | Meaning |
|---|---|
400 | Bad filter — e.g. an unknown status/severity on /issues → invalid_request. |
401 | Bad/missing API key (uniform). |
403 | Key valid but missing the endpoint's scope. |
404 | Resource not in your organization, or nonexistent. |
429 | Per-key or per-org request budget exceeded. |
Ingest (gl_live_…)
| Status | Meaning |
|---|---|
400 | Body not valid JSON (malformed_json) or no events (empty). |
401 | Bad/missing ingest token (uniform). |
403 | The token's log source is disabled (source_disabled). |
413 | Body > 1 MB (payload_too_large) or > 500 events (batch_too_large). |
429 | Per-token or per-org event budget exceeded (rate_limited). |
Note: within a 202, an individual malformed event is reported as rejected in results[] rather than failing the whole request — see ingest.md.
Examples
Uniform auth failure (401):
{ "error": { "code": "unauthorized", "message": "Invalid or expired API key." } }
Missing scope (403):
{ "error": { "code": "forbidden", "message": "This API key is missing the required scope: issues:read." } }
Not found (404):
{ "error": { "code": "not_found", "message": "Issue not found." } }
Invalid filter (400):
{ "error": { "code": "invalid_request", "message": "Invalid severity. One of: CRITICAL, HIGH, MEDIUM, LOW." } }
Rate limited (429):
{ "error": { "code": "rate_limited", "message": "Rate limit exceeded.", "retryAfterSec": 12, "scope": "org" } }
Retry guidance
Retry on network errors, timeouts, 429, and 5xx (with backoff + jitter). Do not retry 400, 401, 403, 404, or 413 — fix the request or credential first. For ingest, reuse idempotency keys on retry.
See also: authentication.md · scopes.md · rate-limits.md.