Error Handling
Handle errors, manage fees, and dispose of sensitive data in Solana wallets.
Use this guide to handle typed transaction errors, transfer failures, fee limits, transaction status errors, and sensitive-data disposal.
Handle Typed Transaction Errors
Starting in beta.15, @tetherto/wdk-wallet-solana re-exports the shared WDK error classes it uses. Branch on these classes instead of matching error-message text.
import {
AssertionError,
MaximumFeeExceededError,
ProviderRequiredError,
ValueError
} from '@tetherto/wdk-wallet-solana'
try {
const result = await account.transfer({
token: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', // USDt mint address
recipient: '11111111111111111111111111111112',
amount: 1000000n
})
console.log('Transfer submitted:', result.hash)
} catch (error) {
if (error instanceof MaximumFeeExceededError) {
console.error('The transfer fee exceeds transferMaxFee')
} else if (error instanceof ProviderRequiredError) {
console.error('Configure a Solana RPC provider')
} else if (error instanceof AssertionError) {
console.error('The wallet account has been disposed')
} else if (error instanceof ValueError) {
console.error('Review the transfer input:', error.message)
} else {
throw error
}
}The package uses ValueError for invalid mnemonics and derivation paths, out-of-range token amounts, mismatched fee payers, malformed transaction signature or hash inputs, and fee estimates that cannot be calculated. An upstream Solana RPC or program failure can still use a provider-specific error type, so keep an unknown-error fallback.
Handle SOL Transfer Errors
Native SOL transfers can fail for reasons including insufficient balance or invalid recipient addresses.
async function safeTransfer(account, wallet) {
try {
const solBalance = await account.getBalance()
const transferAmount = 1000000000n // 1 SOL
if (solBalance < transferAmount) {
throw new Error('Insufficient SOL balance')
}
const quote = await account.quoteSendTransaction({
to: '11111111111111111111111111111112',
value: transferAmount
})
console.log('Estimated fee:', quote.fee, 'lamports')
const result = await account.sendTransaction({
to: '11111111111111111111111111111112',
value: transferAmount
})
console.log('Transaction submitted:', result.hash)
return result
} catch (error) {
console.error('Transaction failed:', error)
throw error
} finally {
account.dispose()
wallet.dispose()
}
}Both transfer and native-send results report submission, not successful execution. Wait for the returned signature with waitForTransaction() and inspect success after the requested commitment before treating the operation as complete.
Handle Prebuilt Transaction Errors
If you pass a prebuilt TransactionMessage, make sure it already has a recent blockhash or durable nonce lifetime, or let WDK inject the latest blockhash for you. If you set feePayer, it must match the wallet address.
Beta.15 reports a mismatched fee payer as ValueError. For a base64 serialized transaction, the account also checks that every required signature is present after adding its own. Missing signatures throw a Solana error with code SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING.
Durable nonce flows still need a valid nonce account and signer setup in the message you provide. WDK preserves that lifetime instead of replacing it.
Manage Fee Limits
Set transactionMaxFee when creating the wallet to cap native SOL sendTransaction() and signTransaction() costs. Set transferMaxFee separately for SPL token transfer() costs. Fee caps reject estimates greater than the configured limit, so an estimate equal to the cap is allowed. Retrieve current network rates with getFeeRates() to make informed decisions.
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'lamports')
console.log('Fast fee rate:', feeRates.fast, 'lamports')
const walletWithCaps = new WalletManagerSolana(seedPhrase, {
provider: 'https://api.mainnet-beta.solana.com',
transactionMaxFee: 10000000n,
transferMaxFee: 10000000n
})Handle Transaction Status Errors
Without a provider, both methods throw ProviderRequiredError. getTransaction() throws ValueError for an invalid base58 signature and NoSuchElementError when a well-formed signature is absent from transaction history. waitForTransaction() propagates the input error, treats an unknown signature as transient during propagation, and throws TimeoutError if the target is not reached within the configured time.
The Solana implementation does not currently return dropped; a never-landed or evicted signature times out. A confirmed or final receipt can still have success: false, so finality must not be used as an execution-success check.
Dispose of Sensitive Data
Call dispose() on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed.
account.dispose()
wallet.dispose()Always call dispose() in a finally block or cleanup handler to ensure sensitive data is cleared even if an error occurs.
Next Steps
- Configuration - Configure providers and fee limits.
- API Reference - Check method signatures and error types.