> ## Documentation Index
> Fetch the complete documentation index at: https://rain-sandbox-trial.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Reference

> Understand Rain SDK error codes, their causes, and how to handle them on iOS and Android.

Both SDKs return consistent error codes, allowing you to implement the same error handling behavior across platforms. Errors are exposed as `RainError` on both platforms: an enum on iOS and a sealed class hierarchy in `com.rain.sdk.error` on Android.

Errors originating from Rain's wallet infrastructure or external wallet providers are mapped to Rain error codes before reaching your application.

## Handle SDK errors

Each error has a code and an associated error type. Use the error type to determine how your application responds and the error code for consistent logging and support.\\

<CodeGroup>
  ```swift iOS theme={null}
  do {
      let result = try await client.sendToken(chainId: chainId, contractAddress: usdc, to: recipient, amount: amount)
  } catch let error as RainError {
      switch error {
      case .insufficientTokenBalance(let requested, let available, let token):
          show("You have \(available) \(token); \(requested) needed.")
      case .transactionPending(let statusId):
          pollLater(statusId)                     // accepted; the hash is still on its way
      case .tokenExpired:
          showLoginScreen()
      default:
          show(error.errorDescription ?? error.code)        // code is "RAIN_xxx"
      }
  }
  ```

  ```kotlin Android theme={null}
  try {
      val result = client.sendToken(chainId, usdc, recipient, amount)
  } catch (e: RainError.InsufficientTokenBalance) {
      show("You have ${e.available} ${e.token}; ${e.requested} needed.")
  } catch (e: RainError.TransactionPending) {
      pollLater(e.statusId)                        // accepted; the hash is still on its way
  } catch (e: RainError.TokenExpired) {
      showLoginScreen()
  } catch (e: RainError) {
      show(e.message ?: e.code)                    // code is "RAIN_xxx"
  }
  ```
</CodeGroup>

Multiple errors may share the same code when they require similar handling. For example, `RAIN_102` covers configuration and input errors, while `RAIN_402` covers insufficient balances.

Use the error type and associated details to provide specific feedback to users.

## Configuration errors

Errors related to SDK initialization, provider configuration, invalid inputs, and unsupported networks.

| Code | iOS case / Android class | Cause | Recommended action |
| :- | :- | :- | :- |
| `RAIN_101` | `sdkNotInitialized` / `SdkNotInitialized` | A wallet operation was called before the SDK client finished initializing. | Resolve the client using `rain.provider(...)` before making wallet requests. |
| `RAIN_102` | `invalidConfig(details:)` / `InvalidConfig` | Invalid configuration or input, including missing contact information, improperly formatted phone numbers, invalid passkeys, or conflicting provider registration. | Inspect the error details and correct the configuration or input. |
| `RAIN_102` | `providerNotRegistered(details:)` / `ProviderNotRegistered` | An operation references a wallet provider that has not been registered. | Register the provider before calling `build()`. |
| `RAIN_102` | `tokenNotFound(token:chainId:)` / `TokenNotFound` | The token contract could not be found on the specified network, or its decimals could not be determined. | Verify the token address and network. Register the token using `registerTokens` if necessary. |
| `RAIN_102` | `invalidRecipient(address:reason:)` / `InvalidRecipient` | The recipient address is invalid, incompatible with the selected network, or references the token's own contract or mint. | Display the returned reason next to the recipient address field. |
| `RAIN_103` | `invalidRpcUrl(_:)` / `InvalidRpcUrl` | The configured RPC endpoint is not a valid URL. | Correct the RPC endpoint in your SDK configuration. |
| `RAIN_104` | `chainNotSupported(chainId:details:)` / `ChainNotSupported` | The requested operation is not supported on the selected network or by the configured wallet provider. | Disable unsupported operations for that network. See **Blockchain support**. |

## Authentication errors

Errors related to authentication, expired sessions, and invalid login credentials.

| Code | iOS case / Android class | Cause | Recommended action |
| - | - | - | - |
| `RAIN_201` | `tokenExpired` / `TokenExpired` | The user has no active session, the session has expired, or the session could not be refreshed. | Return the user to authentication. For external wallet providers, check the session refresh callback. |
| `RAIN_202` | `unauthorized` / `Unauthorized` | The wallet infrastructure rejected the request's credentials. | Reauthenticate the user. Contact Rain if the issue persists. |
| `RAIN_203` | `invalidLoginCode` / `InvalidLoginCode` | The authentication code is incorrect, expired, or has already been used. | Allow the user to retry. Follow the configured resend and retry limits. |

## Network errors

Errors related to network connectivity and transaction processing.

| Code | iOS case / Android class | Cause | Recommended action |
| - | - | - | - |
| `RAIN_301` | `networkError(underlying:)` / `NetworkError` | The RPC endpoint or wallet infrastructure is unavailable or the request timed out. | Retry read operations. For sends, treat the outcome as unknown: the transaction may have been submitted, and history lists confirmed transactions only. Keep the send pending and reconcile against history and the balance before allowing another send. |
| `RAIN_302` | `transactionPending(statusId:)` / `TransactionPending` | Rain accepted the transaction, but its hash was not available before the SDK polling window ended. | Display a pending transaction and refresh history. Retain `statusId` for support and avoid submitting the transaction again. |

## Transaction errors

Errors related to transaction validation, signing, insufficient balances, and collateral withdrawals.

| Code | iOS case / Android class | Cause | Recommended action |
| :- | :- | :- | :- |
| `RAIN_401` | `userRejected` / `UserRejected` | The user canceled the signing request or a wallet provider's confirmation prompt. | Return to the previous screen. No retry is necessary unless the user initiates another transaction. |
| `RAIN_402` | `insufficientFunds(required:available:)` / `InsufficientFunds` | The wallet lacks sufficient native tokens to cover the transfer amount or applicable fees. With gas sponsorship enabled, this primarily applies to native asset transfers and Solana rent. | Display the required amount, available balance, and shortfall. |
| `RAIN_402` | `insufficientTokenBalance(requested:available:token:)` / `InsufficientTokenBalance` | The wallet does not hold enough of the requested token to complete the transfer. | Display the available token balance and required amount. |
| `RAIN_402` | `tokenAccountNotFound(walletAddress:token:)` / `TokenAccountNotFound` | The wallet has never received the requested Solana token and has no associated token account. | Treat the token balance as zero. |
| `RAIN_403` | `transactionSimulationFailed(underlying:)` / `TransactionSimulationFailed` | Transaction simulation indicates the transaction would fail. For sponsored transactions, this error may occur after signing. | Inspect the underlying error before allowing another attempt. Common causes include paused tokens and contract restrictions. |
| `RAIN_404` | `walletUnavailable` / `WalletUnavailable` | The wallet provider did not return a wallet address. | For Rain embedded wallets, prompt the user to log in again. For external providers, confirm that wallet creation is complete. |
| `RAIN_405` | `withdrawalRevertedByNetwork` / `WithdrawalRevertedByNetwork` | A collateral withdrawal was rejected onchain, commonly because a previously issued admin signature was reused after the available withdrawal amount changed. | Request a new admin signature and retry the withdrawal once. See **Card funding and settlement**. |
| `RAIN_406` | `invalidAmount(amount:reason:)` / `InvalidAmount` | The amount is negative, cannot be represented, or exceeds the token's supported decimal precision. | Validate the amount against the token's decimals. Display the returned `reason` when available. |
| `RAIN_407` | `walletNotAuthorized(walletAddress:proxyAddress:)` / `WalletNotAuthorized` | The signing wallet is not authorized to withdraw from the collateral contract. | Verify that the wallet address matches the contract owner. If necessary, update the registered owner wallet. See **Changing the owner wallet**. |

## Provider and internal errors

Errors originating from wallet providers or unexpected SDK states.

| Code | iOS case / Android class | Cause | Recommended action |
| - | - | - | - |
| `RAIN_501` | `providerError(underlying:)` / `ProviderError` | An error occurred in Rain's wallet infrastructure or an external wallet provider and could not be mapped to a more specific error. | Log the error code and underlying details. Contact Rain if the issue persists. |
| `RAIN_502` | `internalError(details:)` / `InternalError` | The SDK encountered an unexpected internal state, such as a malformed signature, an EIP 712 encoding failure, or a configuration operation being applied twice. | Contact Rain support with the error code and associated details. |

## Troubleshooting

Common integration issues and how to resolve them when using Rain's embedded wallet SDKs.

<AccordionGroup>
  <Accordion title="Every SDK call returns RAIN_201 after app launch">
    The SDK may be attempting to resolve the wallet client before the user's saved session has been restored. Call `awaitSessionRestore()` on the provider, then check `hasActiveSession()` before resolving the client.
  </Accordion>

  <Accordion title="Sending on Avalanche returns `RAIN_104`">
    Avalanche supports balance retrieval and transaction history, but outbound transactions are not currently supported through Rain embedded wallets. Disable sending for unsupported networks. For card funding, use a supported network such as Base or Arbitrum. If your application broadcasts transactions independently, `prepareWithdrawal` can still prepare and sign collateral withdrawals without broadcasting them through Rain.
  </Accordion>

  <Accordion title="Sponsored transactions return `RAIN_403` after a delay">
    Sponsored transactions skip local simulation because wallets without native tokens could otherwise fail the simulation before sponsorship is applied. As a result, transaction failures may surface after signing, when Rain's wallet infrastructure processes the transaction. Inspect the underlying error to determine why the transaction reverted. Do not automatically retry without identifying the cause.
  </Accordion>

  <Accordion title="An incorrect login code logs the user out">
    `RAIN_203` indicates an invalid, expired, or previously used authentication code. It should not terminate the user's session or clear the pending authentication challenge. Keep the user on the authentication screen and allow them to retry. Make sure your application handles `RAIN_203` separately from authentication errors that require a new login.
  </Accordion>

  <Accordion title="A previously working wallet returns `RAIN_407` during collateral withdrawal">
    The wallet attempting to sign the withdrawal may no longer match an authorized administrator on the collateral contract. This can occur if the user creates a new account with different login credentials or the wallet address associated with their application changes. Compare the address returned by `getWalletAddress()` with the contract's `adminAddresses`, retrieved using `GET /v1/issuing/users/{userId}/contracts`.
  </Accordion>

  <Accordion title="Wallet balances appear without token symbols">
    The token may not be included in Rain's token registry. On Solana, token mints do not provide symbols directly onchain. Register the token using `registerTokens` and supply its metadata, including its address, symbol, decimals, and name. This allows the SDK to display consistent token information across your application.
  </Accordion>
</AccordionGroup>

## What's next

<Columns cols={2}>
  <Card title="Testing" icon="vial" href="/sdks/embedded-wallets/testing">
    Reproduce these errors safely on testnets.
  </Card>

  <Card title="Sending funds" icon="paper-plane" href="/docs/embedded-wallets/sending-funds">
    How sends, fees, and pending states behave.
  </Card>
</Columns>
