Errors
How the OpenRelay API reports errors, status codes and the JSON error body.
The API uses conventional HTTP status codes. 2xx means success. 4xx means
the request was rejected (and usually shouldn't be retried unchanged). 5xx
means something went wrong on our side.
Error body
Every error response has a JSON body with a human-readable error message and
an optional machine-readable code:
{
"error": "cluster not found",
"code": "not_found"
}Always branch on the HTTP status code first; treat code as a stable hint
and error as a message for logs and humans.
Status codes
| Status | Meaning | What to do |
|---|---|---|
200 | OK | Success. |
400 | Bad Request | Malformed JSON or invalid parameters. Fix the request. |
401 | Unauthorized | Missing, invalid, or expired API key. Check the Authorization header. |
403 | Forbidden | The key is valid but lacks the scope, or targets another org. |
404 | Not Found | The resource doesn't exist (or isn't visible to your org). |
409 | Conflict | The request conflicts with durable current state (e.g. a name clash, or an action invalid for the resource's status). Fix the request; retrying it unchanged will keep failing. |
422 | Unprocessable | The request is well-formed but semantically invalid. |
429 | Too Many Requests | You're being rate limited. Back off and retry; honor Retry-After. |
503 | Service Unavailable | Capacity the request needs is momentarily unavailable (e.g. NODE_AT_CAPACITY while a node turns over, or the fleet is briefly full). Transient: retry the same request with backoff and honor Retry-After. |
5xx | Server Error | A transient problem on our end. Retry with backoff. |
Retrying
Retry safely
Retry only idempotent requests (GET, and creates you can safely repeat)
and only on 429, 503, and 5xx. Use exponential backoff with jitter,
and respect the Retry-After header on 429 and 503 responses when present.
A 503 is transient by contract: a valid request whose capacity is
momentarily unavailable (NODE_AT_CAPACITY, INSUFFICIENT_GPU_CAPACITY,
INSUFFICIENT_CPU_CAPACITY, INSUFFICIENT_IP_CAPACITY). These read live
fleet availability, so they clear as nodes and VMs turn over: retrying the same
create with backoff for a minute or two succeeds. A 409 is a durable conflict
(a name clash, or a node you targeted being offline or on hold); a request
that is structurally impossible (a GPU count your fleet cannot allocate) is a
400. Retrying a 409 or 400 unchanged will not help. Branch on the
status code, not the error code.
# Example: retry a GET up to 5 times with backoff
for i in 1 2 4 8 16; do
if curl -fsS https://api.openrelay.inc/v1/vms/$VM_ID \
-H "Authorization: Bearer $OPENRELAY_API_KEY"; then
break
fi
sleep "$i"
doneDiagnosing failures
For resources that can land in a failed or stuck state (VMs, clusters), the
resource body carries a statusReason field with a human-readable cause: read
it before retrying a create.