---
title: "Every error code, and what to do about it"
description: "Every error code the service returns, grouped by status, with what to do about each."
---

> Documentation Index
> Fetch the complete documentation index at: https://tee.hypetrade.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Every error code, and what to do about it

Every error from every route has one shape:

```json
{
  "error": {
"code": "account_not_found",
"message": "…",
"status": 404,
"requestId": "…"
  }
}
```

Branch on **`error.code`**. Messages are written for humans and may change;
codes are the contract. Keep `requestId` when reporting a problem — it comes
back as the `x-request-id` response header too, and it is what your operator
will ask for.

Some errors carry a fifth field, `error.details`, naming the specific thing
that failed:

```json
{
  "error": {
"code": "scope_denied",
"message": "…",
"status": 403,
"requestId": "…",
"details": { "required": "sign" }
  }
}
```

| Code | `details` |
|---|---|
| `scope_denied` | `required` — the scope the route wanted |
| `invalid_slug` | `expected` — the grammar it wanted |
| `account_locked` | `account` |
| `rpc_not_configured` | `network` |
| `session_capacity_exceeded`, `rpc_capacity_exceeded` | `scope` and `limit` — which ceiling you hit, and what it is |
| `mint_rate_limited`, `account_unlock_rate_limited`, `workspace_creation_rate_limited`, `workspace_recreation_cooldown` | `retryAfterSec` |

Treat `details` as present-or-absent: no other code carries it, and nothing
outside this table is exposed.

## Wait exactly as long as you are told

Every `429` that knows its own deadline sets a **`Retry-After`** response
header, in seconds. That covers the four rate-limit codes above. Read the
header rather than guessing at a backoff — it is the authoritative answer, and
for `workspace_recreation_cooldown` a guess will be badly wrong.

The two capacity codes, `session_capacity_exceeded` and
`rpc_capacity_exceeded`, do **not** set it: their ceilings clear when other
work finishes, not on a clock. Those are the ones to back off exponentially.

## 400 — the request was malformed

| Code | Meaning and fix |
|---|---|
| `invalid_body` | The JSON shape or field combination is wrong. The message names the expected shape. |
| `invalid_slug` | A workspace or account identifier has invalid syntax. Lowercase letters, digits, hyphens; starts alphanumeric. |
| `invalid_parameter` | A path or query selector is malformed — for example `?force=` or `?vm=` with an unaccepted value. |
| `invalid_mnemonic` | The supplied mnemonic could not be parsed. |
| `invalid_private_key` | The supplied private key could not be parsed. |
| `unsupported_network` | The signing engine cannot work with that network. Note this is **not** what a route's `?network=` selector returns for a network the workspace lacks — that is a `404` `account_not_found`. |
| `rpc_endpoint_rejected` | The RPC URL you tried to register was refused at admission. |

## 401 — you are not authenticated

| Code | Meaning and fix |
|---|---|
| `bad_api_key` | `X-Api-Key` or `X-Api-Secret` is missing or wrong. |
| `bad_password` | The workspace password is wrong. |
| `session_expired` | The idle or absolute clock elapsed. Mint a new token and retry — this is routine, not exceptional. |

## 403 — authenticated, but not allowed

| Code | Meaning and fix |
|---|---|
| `scope_denied` | The token is valid but lacks the scope. Re-mint with the scope you need. |
| `permission_denied` | The operation is not permitted for this caller. |
| `export_disabled` | No `exportPublicKey` is registered for the tenant. Your operator must register one. |

## 404 — no such thing

| Code | Meaning and fix |
|---|---|
| `workspace_not_found` | No workspace with that slug for this tenant. |
| `account_not_found` | No such account, wallet, address, or network in this workspace. |
| `not_found` | The route or resource does not exist. |

> **404 is deliberately uninformative**
>
> An address that exists but belongs to another tenant returns exactly the same
> `account_not_found` as one that exists nowhere. The API does not confirm the
> existence of things you cannot reach.

## 409 — conflicts with current state

| Code | Meaning and fix |
|---|---|
| `workspace_exists` | That slug is already in use. |
| `workspace_in_use` | A session is open. Retry with `?force=true` if revoking it is intended. |
| `quota_workspaces_exceeded` | Tenant workspace limit reached. |
| `quota_wallets_exceeded` | Tenant wallet limit reached. |
| `rpc_not_configured` | No usable endpoint for that network. Register one, or ask your operator. |
| `tx_dropped` | The transaction was dropped before inclusion. |
| `tx_aborted` | Submission was aborted before it completed. |

## 422 — well formed, but cannot be done

| Code | Meaning and fix |
|---|---|
| `unsupported_for_kind` | The account, wallet, or chain type cannot perform this otherwise valid operation — typed data on a non-EVM address, a mnemonic from a PK account, a VM the wallet lacks. |
| `weak_password` | The password is shorter than 12 characters. Length is the only rule — no character-class requirement applies. Raised when creating a workspace or an own-password account, never when minting a token. |
| `tx_build_failed` | The transaction could not be constructed from the supplied fields. |

## 423 — locked

| Code | Meaning and fix |
|---|---|
| `workspace_locked` | The workspace is not open. Mint a token. |
| `account_locked` | The account is not currently open. Call the unlock route with the account's password — or, for an account that shares the workspace password, with the workspace password. **Any** account reaches this state once its custody window expires, not only one created with `hasOwnPassword`. |
| `record_locked` | A record is held by another operation. Retry shortly. |

## 429 — slow down, or you are at capacity

| Code | Meaning and fix |
|---|---|
| `mint_rate_limited` | Too many token mints for this tenant. Back off. |
| `account_unlock_rate_limited` | Too many failed account-unlock attempts. |
| `workspace_creation_rate_limited` | Creating workspaces too quickly. |
| `workspace_recreation_cooldown` | That slug was recently deleted and is still cooling down. |
| `session_capacity_exceeded` | Too many workspaces held open at once. Revoke a token you no longer need. |
| `rpc_capacity_exceeded` | Too many concurrent chain operations. Retry with backoff. |

## 500 — the service failed

| Code | Meaning and fix |
|---|---|
| `storage_error` | A storage operation failed. |
| `encrypt_failed` | Encryption failed. |
| `decrypt_failed` | Decryption failed. |
| `algorithm_irreversible` | The requested transformation cannot be reversed. |
| `tx_sign_failed` | Signing did not produce a usable transaction. |

These are not your fault and not fixable by retrying the same request. Capture
`requestId` and report it.

## 501 — not implemented

| Code | Meaning and fix |
|---|---|
| `not_implemented` | The route exists but is not available in this release — see [Addresses](/api/addresses/). |
| `unsupported_operation` | The operation is not supported by the underlying engine. |

## 502, 504, 507 — upstream and capacity

| Status | Code | Meaning and fix |
|---|---|---|
| 502 | `rpc_unreachable` | The RPC endpoint did not respond or answered non-2xx. |
| 502 | `rpc_rejected` | The endpoint responded with a refusal. |
| 502 | `tx_submit_failed` | The endpoint explicitly refused the submission. |
| 504 | `tx_timeout` | Submission timed out. **Check transaction status before resending.** |
| 507 | `disk_full` | The service is out of storage. |

> **tx_timeout is not a failure signal**
>
> Like a `send` returning `unknown`, a timeout means the outcome could not be
> established — the transaction may already be on its way. Look it up with
> [`GET /v1/transactions/{hash}`](/api/transactions/) before submitting again.

## Retry guidance

| Situation | Retry? |
|---|---|
| `429` with a `Retry-After` header | Yes, after exactly that long |
| `429` without one | Yes, with exponential backoff |
| `session_expired` | Yes, after minting a new token |
| `rpc_unreachable`, `rpc_rejected` | Yes, with backoff; consider a different endpoint |
| `tx_timeout`, or `send` returning `unknown` | **Not on `found: false` alone** — that cannot distinguish "never sent" from "in the mempool". See [Send transactions](/guides/send-transactions/) |
| `record_locked` | Yes, shortly |
| Any `400`, `403`, `404`, `422` | No — fix the request |
| `500`-class | No — report with `requestId` |

## Codes from outside the catalog

The codes above are the service's own, and each one names a specific
condition. A few others come from the layer in front of it, before a request
ever reaches a route:

| Status | Code | When |
|---|---|---|
| 400 | `bad_request` | The JSON body could not be parsed at all |
| 401 | `unauthorized` | A rejection with no more specific code |
| 403 | `forbidden` | A rejection with no more specific code |
| 404 | `not_found` | No such route — as distinct from no such record |
| 413 | `payload_too_large` | The request body exceeded the parser's limit, roughly 100 KB |
| 500 | `internal_error` | An unhandled failure. Capture `requestId` and report it |
| — | `request_failed` | A 4xx with no more specific code |

They carry the same envelope as everything else, so branching on `error.code`
still works — but they are generic by construction, and `error.details` is
never present on them.

## Related

- [API conventions](/api/) — the error shape and request tracing
- [Safe usage](/safe-usage/)

Source: https://tee.hypetrade.xyz/errors/index.mdx
