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

# Error Handling

> Error codes, retry logic, and best practices for building reliable integrations.

Every error from the Ralph Studio API returns a consistent JSON body and a standard HTTP status code. Understanding the error structure lets you build integrations that handle failures gracefully instead of crashing.

## Error response format

All errors follow this shape:

```json theme={null}
{
  "detail": "Human readable description of what went wrong"
}
```

Some errors include extra fields:

```json theme={null}
{
  "resource": "wallet-name",
  "detail": "wallet-name not found"
}
```

There is no numeric error code, the HTTP status code is the primary signal. The `detail` string is for logging and debugging, not programmatic branching.

## HTTP status codes

| Status | Name                  | When you see it                                  |
| ------ | --------------------- | ------------------------------------------------ |
| `200`  | OK                    | Request succeeded                                |
| `400`  | Bad Request           | Your request body or query params are invalid    |
| `401`  | Unauthorized          | Missing, expired, or invalid API key             |
| `404`  | Not Found             | The resource (address, block, tx) does not exist |
| `500`  | Internal Server Error | Something went wrong on the node                 |
| `503`  | Service Unavailable   | Node is still syncing                            |
| `504`  | Gateway Timeout       | Node took too long to respond                    |

## 400: Bad Request

You sent something the node could not parse or validate.

```json theme={null}
{
  "detail": "Something bad in the request"
}
```

Common causes:

* Malformed address: Alephium addresses are base58 encoded, not hex
* Invalid timestamp: `fromTs` and `toTs` must be millisecond Unix timestamps
* Missing required field: check the parameters reference for the endpoint
* Amount too small: outputs below the dust limit (\~0.001 ALPH) are rejected

400 errors will not succeed on retry. Fix the request first.

## 401: Unauthorized

```json theme={null}
{
  "detail": "You shall not pass"
}
```

Your API key is missing or wrong. Check:

* The `Authorization` header is present and formatted as `Bearer API_KEY`
* The key belongs to the correct workspace
* The key has not been revoked in the Ralph Studio dashboard

401 errors will not succeed on retry with the same key.

## 404: Not Found

```json theme={null}
{
  "resource": "block-hash",
  "detail": "block-hash not found"
}
```

The resource you requested does not exist. For transactions and blocks this usually means:

* The transaction has not been confirmed yet, check the mempool first
* The block hash is on a fork that was reorganised away
* You are querying a different network (mainnet vs testnet)

For wallet endpoints a 404 means the wallet name does not exist on this node.

## 500: Internal Server Error

```json theme={null}
{
  "detail": "Ouch"
}
```

Something failed inside the node. This is safe to retry with exponential backoff. If it persists across retries check the node logs or the Ralph Studio status page.

## 503: Service Unavailable

```json theme={null}
{
  "detail": "Self clique unsynced"
}
```

The node is still syncing with the network. Balance and transaction data will be incomplete until sync finishes. Check sync status before making data queries:

```bash theme={null}
curl "https://rpc.ralphstudio.xyz/{slug}/infos/self-clique" \
  -H "Authorization: Bearer API_KEY"
```

```json theme={null}
{
  "nodes": [
    {
      "isSynced": true
    }
  ]
}
```

Only proceed when `isSynced` is `true`. 503 errors are safe to retry, back off and wait for the node to catch up.

## 504: Gateway Timeout

```json theme={null}
{
  "detail": "The network is slow"
}
```

The node did not respond in time. This happens during heavy network load or when querying large time ranges. Safe to retry with a smaller time window or after a short delay.

## Retry logic

Not all errors should be retried. Use this decision tree:

| Status | Retry?    | Strategy                                   |
| ------ | --------- | ------------------------------------------ |
| `400`  | No        | Fix the request                            |
| `401`  | No        | Fix the API key                            |
| `404`  | Sometimes | Retry if expecting a pending tx to confirm |
| `500`  | Yes       | Exponential backoff                        |
| `503`  | Yes       | Poll until synced                          |
| `504`  | Yes       | Reduce query range, then retry             |

A simple retry implementation with exponential backoff:

```bash theme={null}
for attempt in 1 2 3 4; do
  response=$(curl -s -o /tmp/response.json -w "%{http_code}" \
    "https://rpc.ralphstudio.xyz/{slug}/infos/version" \
    -H "Authorization: Bearer API_KEY")

  if [ "$response" = "200" ]; then
    cat /tmp/response.json
    break
  fi

  echo "Attempt $attempt failed with status $response, retrying..."
  sleep $((2 ** (attempt - 1)))
done
```

## Validating addresses before sending

A malformed address causes a 400 before the node even processes your request. A quick sanity check before building a transaction:

```bash theme={null}
curl "https://rpc.ralphstudio.xyz/{slug}/addresses/{address}/group" \
  -H "Authorization: Bearer API_KEY"
```

```json theme={null}
{
  "group": 0
}
```

If this returns 400 the address is invalid. If it returns a group between 0 and 3 the address is well-formed and exists on the correct network.

## Checking transaction status before assuming failure

A submitted transaction that returns 404 on the status endpoint is not necessarily lost. It may still be in the mempool:

```bash theme={null}
curl "https://rpc.ralphstudio.xyz/{slug}/transactions/status?txId={txId}&fromGroup=0&toGroup=0" \
  -H "Authorization: Bearer API_KEY"
```

```json theme={null}
{
  "type": "MemPooled"
}
```

Wait for `"type": "Confirmed"` before treating a transaction as complete. Only treat a transaction as failed if it returns `"type": "TxNotFound"` and enough time has passed for it to have been included in a block (\~16 seconds per block).

## Rate limit errors

If you exceed your plan's rate limit you will receive a `429` response:

```json theme={null}
{
  "detail": "Rate limit exceeded"
}
```

The response includes headers telling you when to retry:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1748476860
```

`X-RateLimit-Reset` is a Unix timestamp in seconds. Wait until that time before retrying. See the [rate limits guide](/guides/rate-limits) for per-plan limits and strategies for staying within them.

## Next steps

<CardGroup cols={2}>
  <Card title="Rate limits" icon="gauge" href="/guides/rate-limits">
    Per-plan limits and strategies for staying within them
  </Card>

  <Card title="Submitting a transaction" icon="paper-plane" href="/guides/submitting-transaction">
    Build, sign, and broadcast a transfer
  </Card>
</CardGroup>
