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

# Error Handling

> Error types, codes, and retry behavior in the Trusset SDK

All SDK errors extend `TrussetError` and carry a machine-readable `code`, HTTP `statusCode`, and the server's `requestId` when available. Catch specific subclasses to handle different failure modes.

## Error hierarchy

```typescript theme={null}
import {
  TrussetError,      // Base class - all errors extend this
  AuthError,         // 401 - invalid or expired API key
  ValidationError,   // 400 - bad input caught client-side
  NetworkError,      // 0   - timeout, DNS failure, connection refused
} from '@trusset/sdk'
```

## Catching errors

```typescript theme={null}
try {
  await trusset.customers.manage.get('0xinvalid')
} catch (err) {
  if (err instanceof ValidationError) {
    // Input rejected before hitting the API
    console.error(err.message) // "walletAddress must be a valid Ethereum address"
    return
  }

  if (err instanceof AuthError) {
    // API key is invalid, expired, or the instance is archived
    console.error(err.message, err.requestId)
    return
  }

  if (err instanceof NetworkError) {
    // Request timed out or network is unreachable
    console.error(err.message)
    return
  }

  if (err instanceof TrussetError) {
    // Server returned a non-success response (4xx/5xx)
    console.error(err.code, err.statusCode, err.message, err.requestId)
  }
}
```

## Error properties

Every `TrussetError` instance exposes:

| Property     | Type             | Description                                                   |
| ------------ | ---------------- | ------------------------------------------------------------- |
| `message`    | `string`         | Human-readable error description                              |
| `code`       | `string`         | Machine-readable error code (e.g. `NOT_FOUND`, `TX_REVERTED`) |
| `statusCode` | `number`         | HTTP status code. `0` for network errors.                     |
| `requestId`  | `string \| null` | Server-assigned request ID for support inquiries              |

## Common error codes

| Code                     | Status | Meaning                                            |
| ------------------------ | ------ | -------------------------------------------------- |
| `AUTH_REQUIRED`          | 401    | No API key provided                                |
| `AUTH_FAILED`            | 401    | Invalid or expired API key                         |
| `NOT_FOUND`              | 404    | Resource does not exist                            |
| `CUSTOMER_EXISTS`        | 409    | Duplicate wallet or externalId                     |
| `WALLET_IN_USE`          | 409    | Wallet already assigned to another customer        |
| `SERVICE_NOT_ENABLED`    | 403    | Required service not enabled on this instance      |
| `RELAYER_NOT_CONFIGURED` | 400    | No verified wallet is registered on this instance  |
| `TX_NOT_FOUND`           | 404    | The transaction being confirmed has no receipt yet |
| `TX_REVERTED`            | 400    | The transaction being confirmed reverted on-chain  |
| `VALIDATION_ERROR`       | 400    | Client-side input validation failure               |

KYC proof flow codes (`NOT_VERIFIED`, `HASH_MISMATCH`, `WALLET_MISMATCH`, `STUB_NOT_ALLOWED`, `INVALID_MANIFEST`, `INVALID_HASH`, `PROOF_REQUIRED`, `INVALID_CLAIM_TYPE`, `NO_SELECTED_CLAIMS`) are documented with fixes in the [KYC proofs troubleshooting table](/sdk/customers/kyc-proofs#troubleshooting).

## Retry behavior

Read requests (GET) are retried on transient failures. Write requests are not - identity writes carry on-chain side effects, and blindly repeating an ambiguous failure (5xx, timeout) could submit the same transaction twice. Writes retry only on `429`, where the server rejected the request before doing any work.

| Status                           | GET     | POST / PUT / DELETE |
| -------------------------------- | ------- | ------------------- |
| 408 Request Timeout              | Retried | No                  |
| 429 Too Many Requests            | Retried | Retried             |
| 500 / 502 / 503 / 504            | Retried | No                  |
| Network errors (DNS, connection) | Retried | No                  |
| Timeouts (AbortError)            | Retried | No                  |
| 400, 401, 403, 404, 409          | No      | No                  |

<Tip>
  If an on-chain write fails ambiguously (timeout, 5xx), check `identity.getStatus` or `identity.getClaims` before repeating it - the transaction may have landed anyway. Verification and claim writes are safe to repeat: re-verifying updates the identity, re-adding a claim overwrites it.
</Tip>

Retries use exponential backoff: 1s, 2s, 4s, capped at 10s. Configure via `maxRetries` in the client constructor. Set to `0` to disable.

```typescript theme={null}
const trusset = new TrussetClient({
  apiKey: '...',
  maxRetries: 5,   // up to 5 retries
  timeoutMs: 60_000, // 60s timeout per attempt
})
```

On-chain write methods enforce higher per-request timeout floors regardless of `timeoutMs` (180s; `addClaimsFromProof` 420s), because the backend waits for block confirmations inside the request.

## Logging

Pass a logger to surface retry attempts and request metadata during development:

```typescript theme={null}
const trusset = new TrussetClient({
  apiKey: '...',
  logger: console,
})
```

The logger receives `debug` calls for retry attempts, including the URL and attempt number. No sensitive data (API keys, request bodies) is logged.
