# Error Handling

## Error Types

The SDK exports 7 error types, all extending `SpectrumError`:

| Error                | When                                                  | Key Properties            |
| -------------------- | ----------------------------------------------------- | ------------------------- |
| `ApiError`           | API returns a non-2xx response (except 429/chain 404) | `status`, `body`, `path`  |
| `RateLimitError`     | HTTP 429 from the server                              | `retryAfter` (ms), `path` |
| `ChainNotFoundError` | API returns 404 with "Unknown chain" message          | `chain`                   |
| `TimeoutError`       | Request exceeds `timeout` config                      | `path`                    |
| `NetworkError`       | Connection failure, DNS error, etc.                   | `cause`, `path`           |
| `ValidationError`    | Invalid parameter passed to SDK method                | `field`                   |
| `SpectrumError`      | Base class for all above errors                       | `status?`, `path?`        |

## Usage

```typescript
import {
  Spectrum,
  ApiError,
  RateLimitError,
  ChainNotFoundError,
  TimeoutError,
  NetworkError,
  ValidationError,
} from '@spectrumnodes/sdk';

try {
  await spectrum.core.getBlockHeight('invalid-chain');
} catch (err) {
  if (err instanceof ChainNotFoundError) {
    console.log(`Unknown chain: ${err.chain}`);
  } else if (err instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${err.retryAfter}ms`);
  } else if (err instanceof TimeoutError) {
    console.log(`Timed out on ${err.path}`);
  } else if (err instanceof NetworkError) {
    console.log(`Network error: ${err.cause?.message}`);
  } else if (err instanceof ValidationError) {
    console.log(`Bad param '${err.field}': ${err.message}`);
  } else if (err instanceof ApiError) {
    console.log(`API error ${err.status}: ${err.message}`, err.body);
  }
}
```

## Retry Behavior

Transient errors are retried automatically with exponential backoff:

- **Default max retries:** 3
- **Backoff schedule:** 200ms, 400ms, 800ms (base delay doubles each attempt)
- **Jitter:** +/- 25% randomization on each delay
- **Rate limit:** if `RateLimitError` includes `retryAfter`, that value is used instead of backoff
- **Retryable errors:** `RateLimitError`, `TimeoutError`, `NetworkError`, HTTP 5xx (`ApiError` with status >= 500)
- **Non-retryable:** `ValidationError`, `ChainNotFoundError`, HTTP 4xx (except 429)

Disable retries globally with `retries: 0`, or per-request with `{ noRetry: true }`.
