Honeycluster returns errors in a consistent envelope so clients can handle them uniformly:
Json{ "error": "rate_limited", "message": "Rate limit exceeded, retry after 27 seconds" }
Non-error responses pass through the XRP Ledger's native JSON-RPC shape.
The HTTP status code is chosen to match the class of failure; the body's
error field is the machine-readable identifier.
| Status | error | Cause | Fix |
|---|---|---|---|
429 | rate_limited | Shared-tier fair-use ceiling exceeded, or (private plans) project credit cap hit | Retry after the Retry-After seconds. Sustained traffic: upgrade tier. |
402 | payment_required | (Private plans) tier's cycle has ended with a negative balance | Settle balance from the portal. |
These only appear on authenticated endpoints — the public cluster is keyless and never returns them.
| Status | error | Cause | Fix |
|---|---|---|---|
401 | unauthorized | Missing X-API-Key header on a private endpoint | Add the header. |
401 | invalid_key | Key is malformed or not recognized | Check you copied the full value from the portal. |
401 | revoked_key | Key exists but has been revoked | Issue a new key. |
403 | project_suspended | The project this key belongs to is suspended | Contact billing. |
The XRP Ledger validates method params before executing. These come
through from rippled / Clio in the JSON-RPC envelope's result.error
field, not the top-level error:
result.error | Cause | Fix |
|---|---|---|
invalidParams | A required parameter is missing or malformed | Compare your call against the xrpl.org method reference. |
lgrNotFound | Requested ledger doesn't exist or is outside history window | Verify the ledger index or switch to a full-history node (Honeycluster already uses Clio for history). |
actNotFound | Account hasn't been activated on this ledger | Verify the address is correct and funded. |
txnNotFound | Transaction hash not known to this server | Hash may be wrong, or the tx may not yet have been included in a validated ledger. |
See xrpl.org's universal errors for the complete list.
| Status | error | Cause | Fix |
|---|---|---|---|
502 | upstream_unreachable | All regional nodes failed health checks during the request | Retry; the proxy will route to a different region. |
503 | upstream_degraded | Region is draining; traffic is failing over | Retry without delay. |
504 | upstream_timeout | Backend took longer than the request deadline | Retry; escalate if persistent. |
500 | internal_error | Unclassified server fault inside Honeycluster | Report via support with the X-Request-Id header. |
A resilient client distinguishes transient failures (retry) from terminal failures (abort):
TypeScriptasync function call(body: unknown): Promise<unknown> { const res = await fetch('https://honeycluster.io', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) if (res.ok) return res.json() const payload = await res.json().catch(() => ({ error: 'unknown' })) const code = payload?.error as string | undefined // Transient — retry with backoff if (['rate_limited', 'upstream_unreachable', 'upstream_degraded', 'upstream_timeout'].includes(code ?? '')) { throw new RetryableError(code, res.headers.get('retry-after')) } // Terminal — don't retry throw new Error(`${code ?? 'unknown'}: ${payload?.message ?? res.statusText}`) }
Every response includes an X-Request-Id header — pass it along in
support requests so we can trace the failure through our logs.