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

# Error Handling

> Handle errors gracefully with Chipi's typed error hierarchy and utility functions

## Error Hierarchy

All Chipi SDK errors extend a base `ChipiError` class. Each error type carries specific context to help you handle failures precisely.

```
ChipiError (base)
├── ChipiApiError        → HTTP errors (status code, response body)
├── ChipiAuthError       → Authentication failures (401)
├── ChipiValidationError → Invalid input (400)
├── ChipiWalletError     → Wallet operations (creation, encryption)
├── ChipiTransactionError → Transaction failures (signing, broadcasting)
├── ChipiSessionError    → Session key errors (expired, revoked, not registered)
└── ChipiSkuError        → SKU/billing operations
```

## Type Guards

### `isChipiError(error)`

Check if an error is any Chipi SDK error:

```typescript theme={null}
import { isChipiError } from "@chipi-stack/nextjs";

try {
  await createWalletAsync({ ... });
} catch (error) {
  if (isChipiError(error)) {
    // Typed as ChipiError - has .message, .code
    console.error("Chipi error:", error.message);
  } else {
    // Network error, timeout, etc.
    console.error("Unexpected error:", error);
  }
}
```

### `hasHttpStatus(error)`

Check if an error has an HTTP status code. Useful for retry logic and status-specific handling:

```typescript theme={null}
import { hasHttpStatus } from "@chipi-stack/nextjs";

try {
  await transferAsync({ ... });
} catch (error) {
  if (hasHttpStatus(error)) {
    switch (error.status) {
      case 401:
        // Token expired - refresh and retry
        await refreshToken();
        break;
      case 429:
        // Rate limited - back off
        await delay(5000);
        break;
      case 500:
        // Server error - show retry button
        showRetryUI();
        break;
    }
  }
}
```

## Error Patterns by Type

### API Errors

```typescript theme={null}
import { ChipiApiError } from "@chipi-stack/nextjs";

try {
  await transferAsync({ ... });
} catch (error) {
  if (error instanceof ChipiApiError) {
    console.error(`API error ${error.status}: ${error.message}`);
    // error.status  → HTTP status code (number)
    // error.message → Human-readable error message
  }
}
```

### Session Errors

Session errors include a `.code` field for precise handling:

```typescript theme={null}
import { ChipiSessionError } from "@chipi-stack/nextjs";

try {
  await executeWithSessionAsync({ ... });
} catch (error) {
  if (error instanceof ChipiSessionError) {
    switch (error.code) {
      case "SESSION_EXPIRED":
        // Session validUntil has passed
        await createNewSession();
        break;
      case "SESSION_NOT_REGISTERED":
        // Session not found on-chain
        await registerSession();
        break;
      case "SESSION_REVOKED":
        // Session was explicitly revoked
        await createNewSession();
        break;
      case "SESSION_MAX_CALLS_EXCEEDED":
        // remainingCalls reached 0
        await createNewSession();
        break;
      case "SESSION_ENTRYPOINT_NOT_ALLOWED":
        // Function not in allowedEntrypoints whitelist
        console.error("This action is not permitted by the session");
        break;
      case "SESSION_DECRYPTION_FAILED":
        // Wrong PIN/encryptKey
        promptForPin();
        break;
      case "INVALID_WALLET_TYPE_FOR_SESSION":
        // Wallet is READY, not CHIPI
        console.error("Session keys require a CHIPI wallet");
        break;
    }
  }
}
```

### Session Error Codes Reference

| Code                              | Meaning                           | Recovery                                    |
| --------------------------------- | --------------------------------- | ------------------------------------------- |
| `SESSION_EXPIRED`                 | `validUntil` timestamp has passed | Create and register a new session           |
| `SESSION_NOT_REGISTERED`          | Session key not found on-chain    | Call `addSessionKeyToContract`              |
| `SESSION_REVOKED`                 | Session was explicitly revoked    | Create a new session                        |
| `SESSION_MAX_CALLS_EXCEEDED`      | `remainingCalls` reached 0        | Create a new session with higher `maxCalls` |
| `SESSION_ENTRYPOINT_NOT_ALLOWED`  | Called function not in whitelist  | Register with correct `allowedEntrypoints`  |
| `SESSION_DECRYPTION_FAILED`       | Wrong PIN for session private key | Prompt user to re-enter PIN                 |
| `SESSION_CREATION_FAILED`         | Keypair generation error          | Retry the operation                         |
| `SESSION_INVALID_RESPONSE`        | Malformed contract response       | Check wallet type and contract state        |
| `INVALID_WALLET_TYPE_FOR_SESSION` | Wallet is READY, not CHIPI        | Use a CHIPI wallet for sessions             |

### Wallet Errors

```typescript theme={null}
import { ChipiWalletError } from "@chipi-stack/nextjs";

try {
  await createWalletAsync({ ... });
} catch (error) {
  if (error instanceof ChipiWalletError) {
    // Wallet already exists, encryption failed, etc.
    console.error("Wallet error:", error.message);
  }
}
```

### Auth Errors

```typescript theme={null}
import { ChipiAuthError } from "@chipi-stack/nextjs";

try {
  await transferAsync({ ... });
} catch (error) {
  if (error instanceof ChipiAuthError) {
    // 401 - bearer token invalid or expired
    // Refresh your auth token and retry
    const newToken = await refreshAuthToken();
    await transferAsync({ ...params, bearerToken: newToken });
  }
}
```

## Common Pattern: Unified Error Handler

```typescript theme={null}
import { isChipiError, hasHttpStatus, ChipiSessionError, ChipiAuthError } from "@chipi-stack/nextjs";

function handleChipiError(error: unknown): string {
  if (error instanceof ChipiAuthError) {
    return "Your session has expired. Please sign in again.";
  }

  if (error instanceof ChipiSessionError) {
    if (error.code === "SESSION_EXPIRED" || error.code === "SESSION_MAX_CALLS_EXCEEDED") {
      return "Your session has expired. Creating a new one...";
    }
    return `Session error: ${error.message}`;
  }

  if (hasHttpStatus(error) && error.status === 429) {
    return "Too many requests. Please wait a moment.";
  }

  if (isChipiError(error)) {
    return error.message;
  }

  return "Something went wrong. Please try again.";
}
```

## Related

* [Session Keys Guide](/sdk/guides/session-keys) - Full session key lifecycle
* [Passkeys Guide](/sdk/guides/passkeys) - Biometric authentication
* [Backend Methods](/sdk/backend/methods/sessions) - Server-side error handling

<Tip>
  Need help? Join our [Telegram Community](https://t.me/+e2qjHEOwImkyZDVh) for support.
</Tip>
