> For the complete documentation index, see [llms.txt](https://docs.augustdigital.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.augustdigital.io/developers/typescript-sdk/errors.md).

# Error Handling

Reference for the typed errors thrown by \`@augustdigital/sdk\`. Use this to decide which \`catch\` paths to write and how to recover from each failure class.

All public SDK methods throw typed errors that extend a common base class, `AugustSDKError`. Catch by class for broad handling, or narrow on the `code` field for actionable, per-failure logic.

## Hierarchy

```
AugustSDKError                   // base — every SDK error extends this
├── AugustAuthError              // missing / invalid / forbidden key
├── AugustValidationError        // caller-side input failed validation
├── AugustNetworkError           // network or transport-level failure
├── AugustTimeoutError           // request exceeded its deadline
├── AugustRateLimitError         // backend returned 429 (or equivalent)
├── AugustServerError            // backend returned a non-OK status
└── AugustTransactionError       // transaction sent but not confirmed
```

Every instance carries:

| Property        | Type                       | Description                                                                |
| --------------- | -------------------------- | -------------------------------------------------------------------------- |
| `code`          | `AugustErrorCode`          | Stable string identifier — narrow on this for per-case handling.           |
| `message`       | `string`                   | Human-readable description suitable for surfacing in dev tools.            |
| `correlationId` | `string \| undefined`      | Set from the response `x-correlation-id` header when the SDK received one. |
| `context`       | `Record<string, unknown>?` | Structured payload (e.g. `{ target, amount }`) attached for logging.       |
| `cause`         | `unknown`                  | Original error from the underlying RPC / fetch — preserved for inspection. |
| `stack`         | `string`                   | Native stack trace.                                                        |

`AugustTimeoutError` adds `timeoutMs` (the deadline that elapsed). `AugustRateLimitError` adds an optional `retryAfterMs`. `AugustServerError` adds `status` (the HTTP status code). `AugustTransactionError` adds `signature` (the transaction that was sent).

All instances expose `toJSON()` so `JSON.stringify(err)` returns a useful object — native `Error` serializes to `"{}"` without this.

## Codes

| Class                    | Code                      | When it fires                                                                                                                              | Recommended action                                                                             |
| ------------------------ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `AugustAuthError`        | `AUTH_MISSING_KEY`        | No longer thrown by the fetchers — a missing key now sends an anonymous request, and a route that needs a key answers `AUTH_UNAUTHORIZED`. | Pass `keys.august` into `new AugustSDK({...})` for admin and curator methods.                  |
| `AugustAuthError`        | `AUTH_INVALID_KEY`        | Backend rejected the supplied key (malformed or revoked).                                                                                  | Verify the key value; rotate if needed.                                                        |
| `AugustAuthError`        | `AUTH_FORBIDDEN`          | Backend returned HTTP 403 — key lacks permission for this endpoint.                                                                        | Check the key's permitted scopes; do not retry.                                                |
| `AugustAuthError`        | `AUTH_UNAUTHORIZED`       | Backend returned HTTP 401 — no key was sent, or the key was not accepted.                                                                  | Supply `keys.august` if the route needs one; otherwise re-verify the key and rotate if needed. |
| `AugustValidationError`  | `INVALID_INPUT`           | Required field missing, `NaN` / `Infinity` amount, or JS number above `Number.MAX_SAFE_INTEGER`.                                           | Fix the input before retrying.                                                                 |
| `AugustValidationError`  | `INVALID_ADDRESS`         | Address fails checksum / wrong length, or is not valid for the target chain family (EVM / Solana).                                         | Fix the input.                                                                                 |
| `AugustValidationError`  | `INVALID_CHAIN`           | Chain ID is not in the SDK's allowlist for this operation.                                                                                 | Pass a supported chain.                                                                        |
| `AugustValidationError`  | `INVALID_URL`             | A user-supplied URL failed validation.                                                                                                     | Fix the URL.                                                                                   |
| `AugustValidationError`  | `ACCOUNT_NOT_FUNDED`      | Stellar (Soroban) deposit/redeem source account has never been activated on-chain (zero balance).                                          | Send ≥1 XLM to the address to activate it, then retry.                                         |
| `AugustNetworkError`     | `NETWORK_ERROR`           | Underlying `fetch` / WebSocket failed (DNS, connection refused, offline).                                                                  | Safe to retry with backoff.                                                                    |
| `AugustTimeoutError`     | `TIMEOUT`                 | Request exceeded its deadline (default 90 s, configurable per-call).                                                                       | Backoff + retry; check chain / RPC status.                                                     |
| `AugustRateLimitError`   | `RATE_LIMITED`            | Backend returned HTTP 429 (or equivalent rate-limit signal).                                                                               | Wait `retryAfterMs` before retrying.                                                           |
| `AugustServerError`      | `SERVER_ERROR`            | Backend returned a non-OK status that is not auth / rate-limit / timeout.                                                                  | Inspect `.status` and `.context`; retry conservatively.                                        |
| `AugustTransactionError` | `TRANSACTION_UNCONFIRMED` | Solana: sent, but no outcome was established. `context.reason` says what was seen (e.g. `expired_not_found`: very likely never landed).    | Check `.signature` before resubmitting — it may have landed.                                   |
| `AugustSDKError` (base)  | `UNKNOWN`                 | Wrapped failure from an RPC / contract call. Original error preserved on `.cause`.                                                         | Inspect `.cause` and `.context`; do not retry blindly.                                         |

## Narrowing patterns

### Catch broadly, narrow by code

Best for transactional flows where you want one block of recovery logic per failure category.

```typescript
import {
  AugustAuthError,
  AugustValidationError,
  AugustTimeoutError,
  AugustRateLimitError,
  AugustSDKError,
} from '@augustdigital/sdk';

try {
  await augustSdk.evm.vaultDeposit({
    target: vaultAddress,
    wallet: userAddress,
    amount: '100',
  });
} catch (err) {
  if (err instanceof AugustValidationError) {
    if (err.code === 'INVALID_INPUT') return showFormError(err.message);
    if (err.code === 'INVALID_ADDRESS') return showAddressError();
    if (err.code === 'ACCOUNT_NOT_FUNDED') {
      // Stellar only: the source account needs ≥1 XLM to be activated on-chain.
      // err.message includes the address and the funding hint.
      return showFundingPrompt(err.message);
    }
  }
  if (err instanceof AugustAuthError) {
    return showAuthError('Check your August API key.');
  }
  if (err instanceof AugustTimeoutError) {
    // err.timeoutMs is the deadline that elapsed
    return scheduleRetry(err.timeoutMs);
  }
  if (err instanceof AugustRateLimitError) {
    return scheduleRetry(err.retryAfterMs ?? 5_000);
  }
  if (err instanceof AugustSDKError) {
    // Wrapped downstream failure — inspect cause for the underlying revert / RPC error
    reportError(err.code, err.context, err.cause);
    return;
  }
  throw err;
}
```

### Catch using the type guard

Use `isAugustSDKError` when you receive an `unknown` value (e.g. in a global error handler) and want to keep the rest of the runtime's errors flowing through untouched.

```typescript
import { isAugustSDKError } from '@augustdigital/sdk';

window.addEventListener('unhandledrejection', (event) => {
  if (isAugustSDKError(event.reason)) {
    reportSdkError(event.reason);
    event.preventDefault();
  }
});
```

The guard works across realms (Web Worker, VM contexts) where `instanceof` fails.

### Inspect the original cause

Wrapped errors keep the underlying failure on `.cause`:

```typescript
try {
  await augustSdk.evm.vaultRequestRedeem({ target, wallet, amount });
} catch (err) {
  if (err instanceof AugustSDKError && err.code === 'UNKNOWN') {
    console.error('Underlying error:', err.cause);
    console.error('Context:', err.context);
  }
  throw err;
}
```

For on-chain reverts, `.cause` is the original `ethers` / `viem` error, so revert reasons and gas info remain accessible.

## Retry guidance

| Class                      | Safe to retry?                   | Notes                                                                       |
| -------------------------- | -------------------------------- | --------------------------------------------------------------------------- |
| `AugustValidationError`    | No                               | The input is wrong; retrying will fail the same way.                        |
| `AugustAuthError`          | No                               | Fix the key first.                                                          |
| `AugustNetworkError`       | Yes, with backoff                | Transient by definition.                                                    |
| `AugustTimeoutError`       | Yes, with backoff                | Consider raising `timeoutMs` if the operation is legitimately slow.         |
| `AugustRateLimitError`     | Yes, after `retryAfterMs`        | Honor the suggested wait.                                                   |
| `AugustServerError`        | Conditionally                    | Retry on 5xx with backoff; treat 4xx as terminal.                           |
| `AugustTransactionError`   | Only after checking `.signature` | It may have landed; resubmitting blindly can duplicate a deposit or redeem. |
| `AugustSDKError` `UNKNOWN` | Conditionally                    | Inspect `.cause` first — an on-chain revert is not retryable.               |

## Serialization for logging

Every SDK error implements `toJSON()`, so logging with `JSON.stringify` preserves the structured fields:

```typescript
try {
  await augustSdk.getVault({ vault });
} catch (err) {
  if (err instanceof AugustSDKError) {
    logger.error('sdk_error', JSON.stringify(err));
  }
  throw err;
}
```

The serialized payload includes `name`, `message`, `code`, `correlationId`, `context`, `stack`, and a compact `cause` summary.
