Handle Errors
Handle errors, manage fees, and dispose of sensitive data.
This guide explains how to handle transaction errors, handle transfer errors, diagnose nonce-lane failures, and follow best practices for fee management and memory cleanup.
Transaction Errors
Transactions sent via account.sendTransaction() can fail when the paymaster token balance is insufficient. Wrap calls in a try/catch block:
try {
const result = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000n
})
console.log('UserOperation hash:', result.hash)
} catch (error) {
if (error.message.includes('not enough funds')) {
console.error('Insufficient paymaster token balance')
} else {
console.error('Transaction failed:', error.message)
}
}Transfer Errors
Token transfers via account.transfer() can fail due to insufficient balance or a fee at or above the maximum limit:
try {
const result = await account.transfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000
})
console.log('Transfer UserOperation hash:', result.hash)
} catch (error) {
if (error.message.includes('Exceeded maximum fee')) {
console.error('Transfer cancelled: fee meets or exceeds the configured limit')
} else if (error.message.includes('not enough funds')) {
console.error('Insufficient paymaster token balance')
} else {
console.error('Transfer failed:', error.message)
}
}Nonce-Lane Failures
Lane configuration and bundler behavior can fail in several ways:
- A raw
nonceKeybelow0or above2^192 - 1throwsnonceKey must be within the uint192 range (0 to 2^192 - 1). - Parallel sends from an undeployed Safe or a bundler that does not support nonzero keys can be rejected by the RPC or bundler. Deploy the account with one completed operation first and verify bundler support.
- Two operations submitted concurrently in the same named or default lane can select the same sequence. Both calls can return a UserOperation hash even though one never receives a receipt.
Treat a returned hash as submission evidence, not inclusion. Poll getUserOperationReceipt(hash) with an application timeout. If one same-lane hash never resolves, inspect the bundler response and on-chain lane sequence before retrying; use a fresh lane for independent work or batch dependent calls rather than blindly resubmitting the same operation.
Best Practices
Fee Management
You can retrieve current network fee rates using wallet.getFeeRates():
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal)
console.log('Fast fee rate:', feeRates.fast)Dispose of Sensitive Data
For security, clear sensitive data from memory when a session is complete. Use account.dispose() and wallet.dispose() to securely wipe private keys:
try {
const result = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000n
})
console.log('UserOperation hash:', result.hash)
} finally {
account.dispose()
wallet.dispose()
}Always call dispose() when finished with accounts. Private keys are securely wiped from memory. Disposal is irreversible.