WDK logoWDK documentation

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:

Handle Transaction Errors
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:

Handle Transfer Errors
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 nonceKey below 0 or above 2^192 - 1 throws nonceKey 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():

Get Fee Rates
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:

Dispose Resources
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.

On this page