Errors
HTTP status codes, error objects, and retry guidance.
Eridian returns structured errors on every failed request. The body is stable across REST and SDKs. Correlate with logs using error.request_id and X-Eridian-Request-Id (they match).
Error Object
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-Eridian-Request-Id: axm_req_8f3a2b1c
X-Eridian-RateLimit-Reset: 1718400060
{
"error": {
"type": "eridian.error",
"code": "rate_limit_exceeded",
"message": "Project prj_legal_001 exceeded 300 requests per minute.",
"request_id": "axm_req_8f3a2b1c",
"doc_url": "https://geteridian.com/docs/rate-limits",
"param": null
}
}
object is omitted on errors. SDKs throw EridianError with these fields.
Status Codes
| HTTP | Code | Retry | Meaning |
|---|---|---|---|
| 400 | invalid_request | No | Body failed schema validation |
| 400 | missing_project_id | No | project_id missing from body and header |
| 400 | template_variable_missing | No | Required template variable absent |
| 401 | invalid_api_key | No | Key missing, revoked, or malformed |
| 403 | insufficient_scope | No | Key lacks the required scope |
| 403 | project_archived | No | Project no longer accepts inference |
| 403 | residency_violation | No | Request region conflicts with pin |
| 403 | dual_control_required | No | Mutation queued for second approver |
| 403 | connector_disabled | No | Ops scan against a disabled connector |
| 403 | git_host_forbidden | No | Dev Git app cannot comment |
| 404 | not_found | No | Unknown ID |
| 404 | record_not_retained | No | ZDR or retention clock expired |
| 408 | routing_timeout | Yes | GPT and Gemini hops exceeded timeout |
| 409 | idempotency_conflict | No | Same Idempotency-Key, different body |
| 409 | template_version_conflict | No | Version already published |
| 409 | repository_not_indexed | No | Dev index not ready |
| 409 | diff_too_large | No | Dev review diff over cap |
| 409 | matter_closed | No | Legal write on a closed matter |
| 409 | query_window_too_large | No | Ops log window over cap |
| 409 | segregation_of_duties | No | Risk assignee equals reviewer |
| 409 | evidence_immutable | No | Risk evidence bytes cannot be patched |
| 413 | document_too_large | No | RAG upload exceeds tier limit |
| 422 | structured_output_failed | No | Schema invalid after retries |
| 422 | pii_redaction_failed | Maybe | Redaction engine timed out |
| 429 | rate_limit_exceeded | Yes | Request or token window exhausted |
| 429 | budget_exceeded | No | Monthly hard stop |
| 500 | internal_error | Yes | Unexpected gateway failure |
| 503 | model_unavailable | Yes | No healthy GPT, Gemini, or private hop |
| 503 | cache_unavailable | No retry needed | Request proceeds uncached when documented |
Retry Guidance
Retry only when the table says Yes, and only with exponential backoff plus jitter.
| Attempt | Delay |
|---|---|
| 1 | 250ms |
| 2 | 1s |
| 3 | 4s |
| Stop | Surface the error to the caller |
Honor Retry-After and X-Eridian-RateLimit-Reset on 429. Do not retry POST /v1/inference without an Idempotency-Key; a retry without the header can double-spend.
Python
from eridian import Eridian
from eridian.errors import EridianError, RateLimitError
client = Eridian(api_key="eridian_sk_...", max_retries=3)
try:
client.inference.create(
model="auto",
project_id="prj_legal_001",
messages=[{"role": "user", "content": "Summarize."}],
)
except RateLimitError as exc:
print(exc.request_id, exc.code)
except EridianError as exc:
raise
TypeScript
import { Eridian, EridianError } from "@eridian/sdk";
const client = new Eridian({ apiKey: process.env.ERIDIAN_API_KEY!, maxRetries: 3 });
try {
await client.inference.create({
model: "auto",
projectId: "prj_legal_001",
messages: [{ role: "user", content: "Summarize." }],
});
} catch (error) {
if (error instanceof EridianError) {
console.error(error.code, error.requestId);
}
throw error;
}
See Idempotency and Rate Limits.
Production API credentials are issued with an institution workspace. Contact sales if you need access.