> For the complete documentation index, see [llms.txt](https://spree-finance.gitbook.io/spreefinance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://spree-finance.gitbook.io/spreefinance/developer-guides/stable-points-sp/error-handling.md).

# Error Handling

### SDK Error Classes

#### RpcError

Thrown when the JSON-RPC endpoint returns an error (contract revert, invalid params, execution failure).

```typescript
import { RpcError } from '@spree-finance/spree-evm-sdk';

try {
  const tx = await factory.mint(asset, amount, receiver, false);
} catch (err) {
  if (err instanceof RpcError) {
    console.error(err.message);  // "execution reverted: Pausable: paused"
    console.error(err.code);     // -32000
    console.error(err.data);     // revert data hex
  }
}
```

#### NetworkError

Thrown when the SDK cannot reach the RPC endpoint (DNS failure, timeout, HTTP error).

```typescript
import { NetworkError } from '@spree-finance/spree-evm-sdk';

try {
  const balance = await points.readBalanceOf('0xUser');
} catch (err) {
  if (err instanceof NetworkError) {
    console.error(err.message);  // "Failed to connect to RPC endpoint: ..."
    console.error(err.cause);    // underlying fetch error
  }
}
```

#### DeploymentConflictError

Thrown by `ClientOnboarding.deploy()` when the brand is already deployed on the target chain.

```typescript
import { DeploymentConflictError } from '@spree-finance/spree-evm-sdk';

try {
  await onboarding.deploy({ brandName: 'acme', chainId: 84532n });
} catch (err) {
  if (err instanceof DeploymentConflictError) {
    // Brand already exists; use getDeployedContracts() instead
  }
}
```

#### PollingTimeoutError

Thrown by `ClientOnboarding.deployAndWait()` or `pollTask()` when the deployment does not complete within the timeout window.

```typescript
import { PollingTimeoutError } from '@spree-finance/spree-evm-sdk';

try {
  await onboarding.deployAndWait({ brandName: 'acme', chainId: 84532n });
} catch (err) {
  if (err instanceof PollingTimeoutError) {
    // Deployment still in progress; poll manually with pollTask()
  }
}
```

### Common Contract Errors

| Error                                          | Cause                          | Fix                                    |
| ---------------------------------------------- | ------------------------------ | -------------------------------------- |
| `Pausable: paused`                             | Contract is paused             | Wait for unpause or contact admin      |
| `AccessControl: account 0x... is missing role` | Caller lacks required role     | Grant the role via admin               |
| `ERC20: transfer amount exceeds balance`       | Insufficient token balance     | Check balance before transfer          |
| `ERC20: insufficient allowance`                | Spender not approved           | Call `approve()` first                 |
| `Factory: mint whitelist`                      | Caller not on mint whitelist   | Add to whitelist via Manager           |
| `Factory: redeem whitelist`                    | Caller not on redeem whitelist | Add to whitelist via Manager           |
| `Factory: global cap exceeded`                 | Mint would exceed global cap   | Increase cap or reduce amount          |
| `Factory: no pending request`                  | No redeem request to finalize  | User must call `requestToRedeem` first |
| `PendingSPVault: campaign not active`          | Campaign is inactive           | Activate via `setCampaignActive`       |
| `PendingSPVault: max supply exceeded`          | Campaign hit `maxTotalSupply`  | Create a new campaign or increase cap  |
| `PendingSPVault: daily limit exceeded`         | User hit `dailyMintLimit`      | Wait for next day                      |
| `PendingSPVault: user cap exceeded`            | User hit `maxMintPerUser`      | Cannot mint more to this user          |

### HTTP API Errors

The API returns errors in this format:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_INPUT",
    "message": "amount must be a positive integer"
  }
}
```

| Code             | HTTP Status | Meaning                                |
| ---------------- | ----------- | -------------------------------------- |
| `INVALID_INPUT`  | 400         | Request body failed validation         |
| `UNAUTHORIZED`   | 401         | Missing or invalid API key             |
| `FORBIDDEN`      | 403         | API key lacks permission               |
| `NOT_FOUND`      | 404         | Resource does not exist                |
| `CONFLICT`       | 409         | Operation conflicts with current state |
| `INTERNAL_ERROR` | 500         | Server error; retry or contact support |

### Fee Schedule

| Operation                 | Fee (bps) | Fee (%) |
| ------------------------- | --------- | ------- |
| Mint SP from stablecoins  | 0         | 0.00%   |
| SP to Branded SP          | 0         | 0.00%   |
| Branded SP to SP          | 25        | 0.25%   |
| SP to stablecoin (redeem) | 50        | 0.50%   |
| pSP distribution          | 20        | 0.20%   |
| pSP finalization (settle) | 20        | 0.20%   |

The contract deducts fees from the output amount, not from the input. A 100 SP redemption at 50 bps yields 99.50 USDC worth of stablecoins.
