Skip to main content
The Portal Android SDK uses a structured PortalException hierarchy so you can catch errors at the granularity you need — from individual error cases up to broad categories. Every exception thrown by the SDK is a subclass of PortalException, which itself extends Exception.

Exception hierarchy

PortalException is a sealed class with eight category-level sealed subclasses:
CategoryDescription
PortalException.MpcMPC key generation, backup, recovery, and signing operations
PortalException.StorageGoogle Drive, Passkey, and Keychain storage operations
PortalException.WalletWallet state and availability
PortalException.TransactionTransaction building and asset transfers
PortalException.ApiHTTP requests, RPC calls, and API errors
PortalException.ConnectPortalConnect (WalletConnect) operations
PortalException.ProviderProvider request routing and validation
PortalException.BlockchainChain ID parsing and namespace resolution

Catching exceptions

Because the hierarchy is sealed, you can catch at any level of specificity.

Catch a specific exception

try {
    portal.backupWallet(backupMethod = BackupMethods.Passkey)
} catch (e: PortalException.Mpc.BackupMethodNotConfigured) {
    println("Passkey backup is not configured: ${e.message}")
} catch (e: PortalException.Storage.PasskeyNotSupported) {
    println("This device does not support passkeys: ${e.message}")
}

Catch an entire category

try {
    portal.backupWallet()
} catch (e: PortalException.Mpc) {
    println("MPC operation failed: ${e.message}")
} catch (e: PortalException.Storage) {
    println("Storage operation failed: ${e.message}")
}

Catch any Portal exception

try {
    portal.createWallet().getOrThrow()
} catch (e: PortalException) {
    println("Portal error: ${e.message}")
}

Handle errors from Result-returning methods

Some methods like sendAsset return a Result instead of throwing. Use onFailure or exceptionOrNull() to inspect the error:
portal.sendAsset(
    chainId = "eip155:11155111",
    params = SendAssetParams(to = "0x...", amount = "0.01", token = "NATIVE")
).onSuccess { txHash ->
    println("Transaction sent: $txHash")
}.onFailure { e ->
    when (e) {
        is PortalException.Transaction.SendAssetArgumentError ->
            println("Invalid parameters: ${e.message}")
        is PortalException ->
            println("Portal error: ${e.message}")
        else ->
            println("Unexpected error: ${e.message}")
    }
}

Exception reference

MPC (PortalException.Mpc)

ExceptionDescription
BackupShareNotFoundNo backup share found for the specified backup method.
OrganizationBackupShareNotFoundNo organization backup share found for the specified backup method.
WalletNotFoundNo wallet found for the specified backup method.
MpcVersionNoLongerSupportedThe MPC operation is not supported on the current MPC version. Upgrade to v6.
WalletModificationAlreadyInProgressAnother wallet modification operation (generate, backup, recover) is already running.
MpcResultErrorThe MPC server returned an error. Exposes id (the error identifier string) and error (a PortalError with id and message). See MPC error codes for the full list of server-side error IDs.
UnableToDeriveShareIdCould not derive a share ID from the generated share.
UnableToReadSharesFailed to read shares from storage.
BackendStorageFailedFailed to store data on Portal’s backend.
ClientCipherTextNotFoundNo client cipherText found for the specified backup method during recovery.
UnableToReadFromBackupStorageFailed to read data from backup storage.
UnableToReadFromKeychainFailed to read data from keychain storage.
UnableToNotifyEjectionCould not notify Portal of the ejection request.
NoPrivateKeysEjectedNo private keys could be ejected.
ShareFormattingErrorError formatting shares during ejection.
NoFormattedSharesDataNo data found in the formatted shares response.
InstanceNotAvailableThe MPC instance is not available.
BackupMethodNotConfiguredThe specified backup method has not been configured on the Portal instance. See back up a wallet for configuration steps.
UnsupportedCurveThe specified cryptographic curve is not supported.
Eip155WalletNotFoundNo EIP-155 wallet found. Call createWallet() first.

Storage (PortalException.Storage)

ExceptionDescription
GoogleDriveWriteFailedFailed to write to Google Drive.
GoogleDriveVerificationFailedCould not verify the file was saved to Google Drive.
GoogleDriveFilenameErrorCannot determine filename without a configured API.
GoogleDriveClientDataUnavailableClient data is not available for Google Drive operations.
GoogleDriveHashesErrorError retrieving hashes from Google Drive.
PasskeySessionIdNotFoundNo session ID found during passkey operations.
PasskeyOperationErrorA passkey operation failed.
KeychainValidationErrorKeychain validation failed.
UserRecoverableGDriveExceptionA user-recoverable Google Drive authentication error.
StorageAuthErrorStorage authentication failed.
PasskeyNotSupportedPasskeys are not supported on this device.
PasskeyStorageNotConfiguredPasskey storage has not been configured on the Portal instance.

Wallet (PortalException.Wallet)

ExceptionDescription
WalletNotOnDeviceNo wallet share is available on device storage. The user needs to recover their wallet. See wallet lifecycle states for handling this proactively.
InvalidWalletStateThe wallet is in an invalid state for the requested operation.

Transaction (PortalException.Transaction)

ExceptionDescription
InvalidTransactionResponseThe response from the transaction was an unexpected type.
SendAssetArgumentErrorInvalid arguments passed to sendAsset (missing parameters, invalid chain ID format, or unsupported namespace).

API (PortalException.Api)

ExceptionDescription
YieldApiBadRequestThe Yield API returned a 400 Bad Request error.
HttpRequestFailedAn HTTP request failed with a non-success status code.
RpcErrorAn RPC request failed. Contains code and message fields.
HttpUnauthorizedAn HTTP request returned 401 Unauthorized. Check your API key.

Connect (PortalException.Connect)

ExceptionDescription
InvalidRequestMethodThe WalletConnect request method is invalid.
InvalidRequestParamsThe WalletConnect request parameters are invalid.

Provider (PortalException.Provider)

ExceptionDescription
InvalidRequestParamsThe provider request parameters are invalid.
NoAddressNo address was found for the requested chain.
NoRpcUrlFoundForChainIdNo RPC URL is configured for the given chain ID.
NoSignatureFoundInSignResultThe signing operation completed but returned no signature.
UnsupportedRequestMethodThe request method is not supported on this chain.
NoBindingForSigningApprovalFoundNo signing approval callback is registered.
UserDeclinedApprovalThe user declined the transaction approval prompt.

Blockchain (PortalException.Blockchain)

ExceptionDescription
InvalidChainIdThe chain ID string is malformed (missing : separator). Contains the invalid chainId value.
NoSupportedCurveForChainIdNo supported cryptographic curve found for the given chain ID.
NoSupportedNamespaceForChainIdNo supported namespace found for the given chain ID.

Migration from previous versions

In previous versions of the Android SDK, errors were thrown as generic Error, Exception, or flat PortalException subclasses like SendAssetArgumentError and PortalHttpUnauthorizedException. These legacy classes are now deprecated and will be removed in a future major version.

What changed

  • All generic Error(...) and Exception(...) throws have been replaced with specific PortalException subclasses.
  • Flat exception classes (SendAssetArgumentError, PortalHttpUnauthorizedException, PasskeyNotSupportedException, PasskeyStorageNotConfiguredException, MpcError, InvalidWalletStateError, StorageAuthError) now extend their corresponding PortalException subcategory. Your existing catch blocks will still work, but you should migrate to the new types.

Before and after

// Before — catching a flat legacy class
try {
    portal.backupWallet()
} catch (e: PortalHttpUnauthorizedException) {
    println("Unauthorized: ${e.message}")
} catch (e: Exception) {
    println("Something went wrong: ${e.message}")
}

// After — catching the structured exception
try {
    portal.backupWallet()
} catch (e: PortalException.Api.HttpUnauthorized) {
    println("Unauthorized: ${e.message}")
} catch (e: PortalException.Mpc) {
    println("MPC error: ${e.message}")
} catch (e: PortalException.Storage) {
    println("Storage error: ${e.message}")
}

Deprecated classes mapping

Deprecated classReplace with
SendAssetArgumentErrorPortalException.Transaction.SendAssetArgumentError
PortalHttpUnauthorizedExceptionPortalException.Api.HttpUnauthorized
PasskeyNotSupportedExceptionPortalException.Storage.PasskeyNotSupported
PasskeyStorageNotConfiguredExceptionPortalException.Storage.PasskeyStorageNotConfigured
MpcErrorPortalException.Mpc.MpcResultError
InvalidWalletStateErrorPortalException.Wallet.InvalidWalletState
StorageAuthErrorPortalException.Storage.StorageAuthError