Profiles·Public

ethers

semver>=6.0.0 <7.0.0postconditions42functions21last verified2026-06-12coverage score77%

Postconditions — what we check

  • getBalance · getbalance-rpc-error
    error
    WhenRPC call fails due to network failure, node unreachable, rate limit exceeded, or invalid address format. Throws with error.code one of: SERVER_ERROR (HTTP 4xx/5xx from RPC node), NETWORK_ERROR (no connectivity), TIMEOUT (request timeout exceeded), or INVALID_ARGUMENT (invalid address).
    ThrowsEthersError with error.code = SERVER_ERROR | NETWORK_ERROR | TIMEOUT | INVALID_ARGUMENT
    Required handlingCaller MUST wrap provider.getBalance() in try-catch. Use isError(error, "SERVER_ERROR") to detect RPC node failures, isError(error, "NETWORK_ERROR") for connectivity loss. Uncaught errors crash balance-check routes and wallet UI components.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][2]
  • sendTransaction · sendtransaction-insufficient-funds
    error
    WhenAccount has insufficient ETH to cover transaction cost (gas * gasPrice + value). Throws InsufficientFundsError before the transaction is broadcast.
    ThrowsEthersError with error.code = INSUFFICIENT_FUNDS (InsufficientFundsError)
    Required handlingCaller MUST wrap sendTransaction() in try-catch. Check isError(error, "INSUFFICIENT_FUNDS") to provide user-friendly message about insufficient balance. This is the most common sendTransaction error in production -- check balance with getBalance() before sending.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[3][2]
  • sendTransaction · sendtransaction-nonce-expired
    error
    WhenTransaction nonce has already been used (transaction with same nonce already mined). Common when retrying failed transactions or running concurrent transaction senders.
    ThrowsEthersError with error.code = NONCE_EXPIRED (NonceExpiredError)
    Required handlingCaller MUST catch and retry with a fresh nonce from provider.getTransactionCount(). Common in automated systems that send concurrent transactions or retry on failure.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[2]
  • sendTransaction · sendtransaction-action-rejected
    warning
    WhenUser rejected the transaction in their wallet (MetaMask, WalletConnect, etc.). Only applies when using BrowserProvider or WalletConnect providers.
    ThrowsEthersError with error.code = ACTION_REJECTED (ActionRejectedError)
    Required handlingCaller MUST catch and handle gracefully -- user rejection is not a bug. Use isError(error, "ACTION_REJECTED") to distinguish intentional cancellation from infrastructure failures. Provide a "Transaction cancelled" message to users.
    costlowin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[2]
  • TransactionResponse.wait · wait-transaction-replaced
    error
    WhenTransaction was replaced by another transaction with the same nonce but higher gas (speed-up) or different parameters (cancel). Common during gas price fluctuations when users re-submit with higher fees. Throws with the replacement transaction attached.
    ThrowsEthersError with error.code = TRANSACTION_REPLACED (TransactionReplacedError)
    Required handlingCaller MUST catch TRANSACTION_REPLACED from tx.wait(). This is NOT a fatal error -- the replacement transaction (error.replacement) may have succeeded. Check error.receipt.status to verify outcome. Not handling this causes dApps to show "transaction failed" for speed-up operations that actually succeeded. Pattern: if (isError(e, 'TRANSACTION_REPLACED') && !e.cancelled) { return e.receipt; }
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[2]
  • TransactionResponse.wait · wait-call-exception
    error
    WhenTransaction was mined but execution reverted on-chain. The transaction consumed gas but had no effect. Common with smart contract require() failures, access control rejections, or DeFi slippage violations. This is different from sendTransaction() throwing -- the TX was broadcast and mined, but the smart contract rejected it.
    ThrowsEthersError with error.code = CALL_EXCEPTION (CallExceptionError)
    Required handlingCaller MUST catch CALL_EXCEPTION from tx.wait() to detect on-chain reverts. Use isError(error, "CALL_EXCEPTION"). Inspect error.revert for decoded revert reason if the ABI is known. Critical for token transfers, DeFi operations, and any contract interactions -- uncaught reverting transactions appear as silent failures (gas consumed, nothing happened, no user notification).
    costhighin prodimmediate exceptionusers seelost transactionvisibilitysilent
    Sources[2]
  • TransactionResponse.wait · wait-timeout
    warning
    WhenTransaction was not mined within the timeout period. The transaction may still be pending in the mempool and could be mined later. Throws TimeoutError.
    ThrowsEthersError with error.code = TIMEOUT (TimeoutError)
    Required handlingCaller MUST catch TIMEOUT from tx.wait() and handle pending state explicitly. The transaction is NOT failed -- it may still be mined. Store the transaction hash and allow users to check status later. Do NOT mark orders/payments as failed on timeout.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[2]
  • provider.estimateGas · estimategas-call-exception
    error
    WhenThe transaction would revert if executed at the current block state. Common when: (1) contract require() conditions are not met, (2) caller lacks permissions, (3) token approval is insufficient, (4) slippage exceeds tolerance in DeFi.
    ThrowsEthersError with error.code = CALL_EXCEPTION (CallExceptionError)
    Required handlingCaller MUST wrap estimateGas() in a separate try-catch from sendTransaction(). Both throw independently. Use isError(error, "CALL_EXCEPTION") and inspect error.revert for the decoded revert reason to give users specific feedback.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[4][2]
  • provider.estimateGas · estimategas-insufficient-funds
    error
    WhenSender account has insufficient ETH to cover minimum gas cost for the transaction. estimateGas fails fast before broadcasting.
    ThrowsEthersError with error.code = INSUFFICIENT_FUNDS (InsufficientFundsError)
    Required handlingCaller MUST catch INSUFFICIENT_FUNDS from estimateGas() separately from sendTransaction(). Both can throw it independently.
    costmediumin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[2]
  • provider.call · call-revert-exception
    error
    WhenThe smart contract execution reverts during eth_call simulation. Common causes: (1) view/pure function has a require() that fails, (2) wrong ABI (calling non-existent function), (3) calling with unauthorized address. Revert data is attached to the error and can be decoded if the ABI is known.
    ThrowsEthersError with error.code = CALL_EXCEPTION (CallExceptionError) -- error.data contains raw revert bytes
    Required handlingCaller MUST wrap provider.call() in try-catch. Use isError(error, "CALL_EXCEPTION"). Decode revert reason: interface.parseError(error.data). Always wrap contract read calls in try-catch -- contracts can revert on reads too. Uncaught revert from call() crashes view-layer components displaying contract state.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5][2]
  • provider.broadcastTransaction · broadcast-insufficient-funds
    error
    WhenThe signed transaction would overdraft the sender's ETH balance. RPC node rejects before adding to mempool. Common when broadcasting offline-signed transactions where balance changed between signing and broadcasting.
    ThrowsEthersError with error.code = INSUFFICIENT_FUNDS (InsufficientFundsError)
    Required handlingCaller MUST wrap broadcastTransaction() in try-catch. Particularly important in batch-signing workflows where balance may change between signing and broadcast.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[6][2]
  • provider.broadcastTransaction · broadcast-nonce-expired
    error
    WhenThe nonce in the signed transaction has already been used. Common in batch-signing workflows where some transactions were already sent, or offline-signed transactions are broadcast out of order.
    ThrowsEthersError with error.code = NONCE_EXPIRED (NonceExpiredError)
    Required handlingCaller MUST catch NONCE_EXPIRED and re-sign with fresh nonce from getTransactionCount(). Critical for automated transaction systems that sign and broadcast asynchronously.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[2]
  • Wallet.fromEncryptedJson · from-encrypted-json-invalid-password
    error
    WhenPassword is incorrect. The scrypt key derivation produces a key that fails MAC verification in the keystore. Most common error when loading wallets -- wrong passwords, encoding mismatches (UTF-8 vs bytes), or copy-paste errors.
    ThrowsError with message about invalid password / MAC mismatch
    Required handlingCaller MUST wrap Wallet.fromEncryptedJson() in try-catch. Wrong password throws -- it does NOT return null. Provide a user-friendly "Incorrect password" message. Never log the attempted password. Critical for server-side wallet management.
    costhighin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[7]
  • Wallet.fromEncryptedJson · from-encrypted-json-corrupt-keystore
    error
    WhenThe JSON string is malformed, missing required fields, or uses an unsupported cipher (not aes-128-ctr). Throws UNSUPPORTED_OPERATION for unknown ciphers, or JSON parse errors for malformed JSON.
    ThrowsEthersError with error.code = UNSUPPORTED_OPERATION | JSON.parse SyntaxError
    Required handlingCaller MUST validate the keystore JSON using isKeystoreJson() before calling fromEncryptedJson(). Database corruption or filesystem errors can produce truncated keystores that throw on decryption.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8]
  • provider.waitForTransaction · wait-for-transaction-timeout
    warning
    WhenThe transaction is not mined within the timeout period. If timeout is set and expires, throws TIMEOUT. The transaction may still be pending -- it is NOT cancelled.
    ThrowsEthersError with error.code = TIMEOUT (TimeoutError)
    Required handlingCaller MUST catch TIMEOUT and NOT mark the transaction as failed. Store the transaction hash and allow users to poll status later. Network congestion can delay mining by minutes or hours for low-fee transactions.
    costmediumin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[9][2]
  • provider.getLogs · getlogs-range-too-large
    error
    WhenThe block range (fromBlock..toBlock) is too large for the RPC node. Infura and Alchemy reject ranges returning more than 10,000 log entries. Also throws on invalid filter parameters or general RPC node errors (SERVER_ERROR).
    ThrowsEthersError with error.code = SERVER_ERROR (ServerError)
    Required handlingCaller MUST wrap getLogs() in try-catch and implement chunked pagination for large block ranges. Split queries into chunks (e.g., 2000 blocks at a time). Not handling this crashes indexing jobs and event-sync workers that process large block ranges at startup.
    costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilent
    Sources[10][2]
  • ContractFactory.deploy · deploy-insufficient-funds
    error
    WhenThe deploying account lacks sufficient ETH to cover the deployment gas cost. Contract deployments can be expensive (depends on bytecode size + gas price). Throws before the transaction is broadcast -- account balance is checked by the RPC node.
    ThrowsEthersError with error.code = INSUFFICIENT_FUNDS (InsufficientFundsError)
    Required handlingCaller MUST wrap ContractFactory.deploy() in try-catch. Check isError(error, "INSUFFICIENT_FUNDS") and verify deployer balance before attempting deployment. Consider pre-checking with estimateGas() on the deploy transaction. Uncaught errors crash deployment scripts and dApp setup flows.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[11][2]
  • ContractFactory.deploy · deploy-unsupported-operation
    error
    WhenThe runner (signer) attached to the ContractFactory does not support sending transactions. Common when using a Provider (read-only) instead of a Signer, or when the Signer lacks wallet connectivity (e.g., not connected to MetaMask in a browser context).
    ThrowsEthersError with error.code = UNSUPPORTED_OPERATION
    Required handlingCaller MUST ensure the ContractFactory is created with a Signer that has sendTransaction capability, not just a Provider. Verify runner type before deployment. Common in server-side scripts where Provider and Signer are confused.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[11][2]
  • Contract.waitForDeployment · waitfordeployment-constructor-reverted
    error
    WhenThe deployment transaction was mined but the contract constructor reverted on-chain. This is a CALL_EXCEPTION from deployTx.wait() -- the transaction consumed gas but the contract was NOT deployed. The contract address will have no code. Common when constructor require() conditions are not met (e.g., invalid initial state, access control).
    ThrowsEthersError with error.code = CALL_EXCEPTION (CallExceptionError) from deployTx.wait()
    Required handlingCaller MUST wrap waitForDeployment() in try-catch. Check isError(error, "CALL_EXCEPTION") to detect constructor revert. Inspect error.revert for decoded revert reason if ABI is known. Uncaught constructor reverts leave application state inconsistent -- deployment scripts assume contract is ready but no code exists at the address.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[12][2]
  • Contract.waitForDeployment · waitfordeployment-transaction-replaced
    warning
    WhenThe deployment transaction was replaced (speed-up or cancel) before being mined. TRANSACTION_REPLACED from deployTx.wait(). Common in scripts that speed-up slow deployments by resubmitting with higher gas, or cancel/retry deployments.
    ThrowsEthersError with error.code = TRANSACTION_REPLACED (TransactionReplacedError)
    Required handlingCaller MUST catch TRANSACTION_REPLACED -- the replacement deployment tx (error.replacement) may have succeeded. Check error.cancelled to determine if deployment was actually cancelled vs speed-up. If error.receipt.status === 1, the replacement succeeded.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]
  • Contract.waitForDeployment · waitfordeployment-unsupported-operation
    error
    WhenThe contract runner does not have a provider attached. Throws UNSUPPORTED_OPERATION with operation="waitForDeployment" when polling for deployment without a deployment transaction available (e.g., contract attached to an address without a deploy tx).
    ThrowsEthersError with error.code = UNSUPPORTED_OPERATION
    Required handlingEnsure the Contract instance was returned from ContractFactory.deploy() (which attaches the deployment tx) OR that the runner has a provider for block polling.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[12][2]
  • Contract.queryFilter · queryfilter-range-too-large
    error
    WhenThe block range (fromBlock..toBlock) causes getLogs to return more than 10,000 results, causing Infura, Alchemy, and most public RPC nodes to reject with SERVER_ERROR. Common when querying Transfer events from genesis block or using wide block ranges at startup. Default (fromBlock=0, toBlock="latest") is almost always rejected on mainnet.
    ThrowsEthersError with error.code = SERVER_ERROR (ServerError)
    Required handlingCaller MUST wrap Contract.queryFilter() in try-catch and implement chunked pagination. Use narrow block ranges (e.g., 2000 blocks at a time). Particularly important for indexing flows that process event history at startup -- uncaught errors crash the entire indexing job and leave contract state out of sync.
    costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilent
    Sources[13][2]
  • Contract.queryFilter · queryfilter-no-provider
    error
    WhenThe Contract instance's runner does not have a provider attached. Throws UNSUPPORTED_OPERATION with operation="queryFilter". Common when Contract is instantiated with a bare Signer that has no provider, or with null runner.
    ThrowsEthersError with error.code = UNSUPPORTED_OPERATION
    Required handlingEnsure the Contract instance has a provider-connected runner before calling queryFilter. Use contract.connect(providerOrSigner) to attach a provider.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[13][2]
  • wallet.signTypedData · signtypeddata-no-provider-for-ens
    error
    WhenThe typed data contains ENS names (e.g., in domain.verifyingContract or value fields) but the wallet is not connected to a provider. Throws UNSUPPORTED_OPERATION with operation="resolveName". Common in offline signing setups where a bare Wallet is used without a JsonRpcProvider, but the typed data schema references ENS names.
    ThrowsEthersError with error.code = UNSUPPORTED_OPERATION
    Required handlingCaller MUST either: (1) ensure the wallet is connected to a provider (wallet.connect(provider)), or (2) resolve all ENS names to addresses before passing to signTypedData. Safest approach is to always connect a provider when using signTypedData with external data that may contain ENS names.
    costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[14][2]
  • wallet.signTypedData · signtypeddata-unconfigured-ens
    warning
    WhenThe typed data contains an ENS name that resolves to null (unregistered or expired ENS domain). Throws UNCONFIGURED_NAME error. Less common than the no-provider case but can occur in production when user-supplied domain structs contain ENS names.
    ThrowsEthersError with error.code = UNCONFIGURED_NAME
    Required handlingCaller MUST catch UNCONFIGURED_NAME and surface a user-facing error indicating the ENS name is unresolvable. Pre-validate any user-supplied ENS names with provider.resolveName() before passing to signTypedData.
    costlowin prodimmediate exceptionusers seeauthentication failurevisibilityvisible
    Sources[2]
  • BrowserProvider.getSigner · browserprovider-getsigner-action-rejected
    error
    WhenUser denies the MetaMask/WalletConnect permission popup triggered by eth_requestAccounts. Also fires when the request has expired ("expired" reason) or another pending request blocks the new one ("pending" reason). This is the most common wallet interaction error -- users frequently dismiss the wallet connection popup.
    ThrowsEthersError with error.code = ACTION_REJECTED (ActionRejectedError) -- error.action = 'requestAccess', error.reason = 'rejected' | 'expired' | 'pending'
    Required handlingCaller MUST wrap BrowserProvider.getSigner() in try-catch. Use isError(error, "ACTION_REJECTED") to distinguish user rejection from infrastructure failure. Provide a "Please connect your wallet" message, NOT a generic "Something went wrong." Not catching ACTION_REJECTED crashes the wallet connection flow and leaves the app in an unusable state for the user.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[15][2]
  • BrowserProvider.getSigner · browserprovider-getsigner-no-wallet
    error
    WhenNo Web3 wallet is installed or accessible. BrowserProvider constructor will fail if window.ethereum is not available, but getSigner() can additionally throw UNSUPPORTED_OPERATION when the wallet lacks eth_requestAccounts support (e.g., older wallet versions, restricted browser contexts, mobile WebViews).
    ThrowsEthersError with error.code = UNSUPPORTED_OPERATION -- or plain Error('no such account')
    Required handlingCaller MUST detect missing wallet before calling getSigner(). Check for window.ethereum or use BrowserProvider.discover() first. Always provide a "Install MetaMask" or "No wallet found" fallback. Uncaught errors leave dApp silently broken for users without wallets (which is common on desktop browsers without extensions).
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[15][2]
  • Wallet.encrypt · encrypt-invalid-scrypt-options
    warning
    WhenInvalid scrypt parameters are passed in options.scrypt. N must be a positive power of 2 (e.g., 1024, 8192, 131072). r and p must be positive integers. If invalid, throws an INVALID_ARGUMENT error with argument name "options.N", "options.r", or "options.p". Common when developers accidentally pass non-power-of-2 N values or 0 for r or p.
    ThrowsEthersError (INVALID_ARGUMENT) -- assertArgument failure with 'invalid scrypt N parameter'
    Required handlingCaller MUST validate scrypt options before calling encrypt(). Always use the default parameters (omit options.scrypt entirely) in production unless you have specific requirements. Never set N below 8192 for production wallets -- lower values are insecure. Wrap encrypt() in try-catch to catch INVALID_ARGUMENT from malformed options.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[16]
  • Wallet.encrypt · encrypt-oom-crash
    error
    WhenThe scrypt KDF with default parameters (N=131072, r=8, p=1) requires approximately 128MB of RAM. In serverless functions (Lambda, Vercel Functions) with memory limits below 256MB, or in containers with strict memory cgroups, the underlying WebAssembly scrypt implementation can exhaust available memory and cause the process to crash or throw an out-of-memory error. The error message varies by runtime (RangeError, ENOMEM, or uncaught exception from the scrypt WASM module).
    ThrowsRangeError: WebAssembly.Memory.grow(): Out of memory | or process-level OOM crash
    Required handlingCaller MUST ensure sufficient memory is available when calling Wallet.encrypt() in serverless or containerized environments. Either increase memory limits to 512MB+, or use reduced scrypt parameters (N=8192 minimum — only for non-production key storage). Never call encrypt() in memory-constrained Lambda functions with default parameters. Consider offloading key encryption to a dedicated service with adequate memory.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[16]
  • JsonRpcProvider.getSigner · jsonrpc-getsigner-no-such-account
    error
    WhenThe requested account index or address is not available on the JSON-RPC node. Throws a plain Error (not an EthersError) with message "no such account" when numeric index >= accounts.length, or "invalid account" when the address is not in the managed account list. Common when using Hardhat/Anvil test accounts by index (indices 10+) or when the target node has no unlocked accounts (public RPC endpoints).
    ThrowsError with message 'no such account' | 'invalid account' (plain Error, not EthersError)
    Required handlingCaller MUST wrap JsonRpcProvider.getSigner() in try-catch. Note: throws a plain Error, NOT an EthersError, so isError() will not work here. Use standard instanceof Error check. In scripts targeting local Hardhat/Anvil nodes, validate the account index before calling getSigner(). For production code, always use a Wallet connected to a provider instead of getSigner() -- public RPC endpoints never have managed accounts.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[17][2]
  • Contract.method · contract-method-call-exception
    error
    WhenA state-changing contract method (e.g., transfer, mint, approve, vote) is called without a try-catch block. The contract reverts due to a custom error or require() failure (e.g., insufficient balance, unauthorized caller, invalid state). The EVM returns revert data which ethers decodes into a CALL_EXCEPTION EthersError. Common in DeFi: transferring more tokens than balance, calling mint() after limit reached, voting twice on same proposal.
    ThrowsEthersError with code CALL_EXCEPTION (error.code === 'CALL_EXCEPTION')
    Required handlingCaller MUST wrap contract method calls in try-catch. Use isError(error, 'CALL_EXCEPTION') to specifically handle contract reverts. Check error.revert?.name for the custom error name and error.reason for the require() message. Distinguish CALL_EXCEPTION (contract rejected the operation) from INSUFFICIENT_FUNDS (insufficient ETH for gas) and NONCE_EXPIRED (transaction management issue).
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[2][18]
  • Contract.method · contract-method-no-signer
    error
    WhenA state-changing contract method is called on a Contract instance connected to a read-only Provider (not a Signer). Common pattern: `const contract = new Contract(addr, abi, provider)` followed by `await contract.transfer(...)`. The contract runner fails the canSend() check and throws immediately before any RPC call is made.
    ThrowsEthersError with code UNSUPPORTED_OPERATION (error.code === 'UNSUPPORTED_OPERATION', error.operation === 'sendTransaction')
    Required handlingCaller MUST ensure the Contract is connected to a Signer, not a Provider, when calling state-changing methods. Use `contract.connect(signer)` or pass a Signer to the constructor. For read-only calls (view/pure functions), a Provider is sufficient. Add runtime check: if (!(contract.runner instanceof ethers.Signer)) throw new Error('signer required').
    costmediumin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[18][2]
  • provider.send · provider-send-unsupported-method
    error
    Whenprovider.send() is called without a try-catch and the JSON-RPC method is not supported by the connected node (e.g., calling Infura with 'trace_transaction' which requires Alchemy's trace API, or calling 'eth_getProof' on a light node). The node returns error code -32601 ("Method not found"). ethers maps this to UNSUPPORTED_OPERATION. Also thrown when calling send() after the provider is destroyed.
    ThrowsEthersError with code UNSUPPORTED_OPERATION (error.code === 'UNSUPPORTED_OPERATION')
    Required handlingCaller MUST wrap provider.send() in try-catch. Use isError(error, 'UNSUPPORTED_OPERATION') to detect unsupported method errors. For provider-capability detection, call a test method before deploying to production and fail fast with a clear configuration error. Consider falling back to alternative providers if the primary RPC lacks the required method.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[19][2]
  • provider.send · provider-send-network-error
    warning
    Whenprovider.send() is called without a try-catch and the RPC call fails due to network connectivity issues (WebSocket disconnect, HTTP timeout, connection refused). These propagate as SERVER_ERROR or NETWORK_ERROR from the underlying transport. Common in serverless functions with cold start network initialization delays.
    ThrowsEthersError with code SERVER_ERROR or NETWORK_ERROR (error.code === 'SERVER_ERROR' | 'NETWORK_ERROR')
    Required handlingCaller MUST wrap provider.send() in try-catch and handle SERVER_ERROR and NETWORK_ERROR separately from UNSUPPORTED_OPERATION. For resilience, implement retry logic with exponential backoff for SERVER_ERROR. For NETWORK_ERROR, verify provider connectivity before making calls or use a FallbackProvider for automatic failover.
    costmediumin proddelayed failureusers seedegraded performancevisibilitysilent
    Sources[19]
  • wallet.signTransaction · signtransaction-from-address-mismatch
    error
    Whenwallet.signTransaction({ from, ... }) is called without a try-catch and the `from` field does not match this wallet's address. ethers refuses to sign a transaction that claims to be from a different address than the signing key owns — this is a deliberate safety check that prevents accidentally signing transactions intended for a different wallet (common in multi-wallet apps and key-rotation flows).
    ThrowsEthersError with code INVALID_ARGUMENT and argument 'tx.from' (error.code === 'INVALID_ARGUMENT', error.argument === 'tx.from')
    Required handlingCaller MUST wrap wallet.signTransaction() in try-catch and handle INVALID_ARGUMENT. The typical fix is to either omit `from` from the TransactionRequest (ethers will fill it in correctly) or verify it matches `await wallet.getAddress()` before calling. Use isError(error, 'INVALID_ARGUMENT') to detect. Silent swallowing here causes "stuck transaction" debugging nightmares because the offline-signing flow fails before broadcast and the broadcaster has no signed payload to relay.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[20][2]
  • wallet.signTransaction · signtransaction-invalid-transaction-fields
    error
    Whenwallet.signTransaction(tx) is called without a try-catch and Transaction.from(tx) rejects the TransactionRequest because of invalid or inconsistent fields. Common causes: type-2 (EIP-1559) transaction missing maxFeePerGas or maxPriorityFeePerGas, type-1 (EIP-2930) missing accessList, type-3 (EIP-4844) blob transactions missing blobVersionedHashes, type-4 (EIP-7702) authorizationList rejected on chains that have not yet activated Pectra, chainId mismatch with provider, gasLimit out of uint64 range, or value/nonce/gasPrice not coercible to bigint.
    ThrowsEthersError with code INVALID_ARGUMENT (error.code === 'INVALID_ARGUMENT')
    Required handlingCaller MUST wrap wallet.signTransaction() in try-catch and handle INVALID_ARGUMENT. For type-2 transactions, populate maxFeePerGas/maxPriorityFeePerGas via provider.getFeeData() before signing. For type-4 (EIP-7702) flows, verify the chain has activated the EIP before constructing the authorizationList. For dynamic-fee transactions on legacy chains, fall back to type-0 by setting `type: 0` and `gasPrice` explicitly. Surface clear error to UI when a transaction is unsignable so the user can adjust parameters.
    costmediumin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[20][21]
  • wallet.authorize · authorize-no-provider-for-auto-fill
    error
    Whenwallet.authorize({ address: '0x...' }) is called without a try-catch and either chainId or nonce is omitted from the auth object. ethers needs a provider to fetch the missing field — chainId via provider.getNetwork() and nonce via wallet.getNonce() which calls provider.getTransactionCount(). A wallet constructed without a provider (e.g., `new Wallet(privateKey)` instead of `new Wallet(privateKey, provider)`) cannot auto-populate these and will throw UNSUPPORTED_OPERATION.
    ThrowsEthersError with code UNSUPPORTED_OPERATION (error.code === 'UNSUPPORTED_OPERATION', error.operation === 'getNetwork' or 'getTransactionCount')
    Required handlingCaller MUST wrap wallet.authorize() in try-catch and either (a) attach a provider via wallet.connect(provider) before calling, or (b) supply both chainId and nonce explicitly: `wallet.authorize({ address, chainId: 1, nonce })`. For sponsored-gas flows where the sponsor knows the chainId in advance, prefer option (b) to avoid unnecessary RPC calls. Use isError(error, 'UNSUPPORTED_OPERATION') to detect.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
  • wallet.authorize · authorize-invalid-delegate-address
    error
    Whenwallet.authorize({ address }) is called without a try-catch and `address` is not a valid checksummed/lowercased Ethereum address string. authorizeSync runs an assertArgument check on typeof address === 'string' and then resolveAddress + getAddress validate the format. Passing a Promise, undefined, an empty string, or a malformed hex string raises INVALID_ARGUMENT. Common in session-key flows where the delegate contract address comes from an API response that may have null fields.
    ThrowsEthersError with code INVALID_ARGUMENT and argument 'auth.address' (error.code === 'INVALID_ARGUMENT')
    Required handlingCaller MUST wrap wallet.authorize() in try-catch and validate the delegate address BEFORE calling: use ethers.isAddress(address) to pre-check. Handle INVALID_ARGUMENT with a clear error to the UI ("Session key contract address is invalid"). Silent swallowing causes the user to see a generic "transaction failed" message with no way to recover, because the authorization needed for the type-4 transaction is never produced.
    costmediumin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[22][25]
  • Signer.populateTransaction · populatetransaction-no-provider
    error
    Whensigner.populateTransaction(tx) is called without a try-catch and the Signer has no provider attached. Internally populateTransaction calls checkProvider(this, "populateTransaction") which throws UNSUPPORTED_OPERATION when this.provider is null — and it must call provider.getNetwork() to fetch chainId, provider.getTransactionCount() for nonce, provider.estimateGas() for gasLimit, and provider.getFeeData() for fee fields. All four are unavoidable unless every field is pre-populated. Common in cold-wallet flows that construct `new Wallet(pk)` without a provider intending to sign offline, then accidentally invoke populateTransaction instead of just Transaction.from(...).
    ThrowsEthersError with code UNSUPPORTED_OPERATION (error.code === 'UNSUPPORTED_OPERATION', error.operation === 'populateTransaction')
    Required handlingCaller MUST wrap signer.populateTransaction() in try-catch and either (a) attach a provider via signer.connect(provider) or new Wallet(pk, provider) before calling, or (b) skip populateTransaction entirely and use Transaction.from(tx) directly when every field (nonce, gasLimit, chainId, fee data) is already populated by the caller (typical for relayer flows where the orchestrator pre-computes everything). Use isError(error, 'UNSUPPORTED_OPERATION') to detect.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[26][27]
  • Signer.populateTransaction · populatetransaction-chainid-mismatch
    error
    Whensigner.populateTransaction({ chainId, ... }) is called without a try-catch and the supplied tx.chainId does not match the connected provider's network chainId. ethers refuses to populate a transaction that would be signed for a different chain than the provider is connected to — a safety check that prevents accidentally broadcasting a mainnet-signed transaction to a testnet provider (or vice versa) and prevents replay-attack confusion. Common in multi-chain dApps that switch providers but forget to clear stale tx.chainId values from the request builder.
    ThrowsEthersError with code INVALID_ARGUMENT and argument 'tx.chainId' (error.code === 'INVALID_ARGUMENT', error.argument === 'tx.chainId')
    Required handlingCaller MUST wrap signer.populateTransaction() in try-catch and handle INVALID_ARGUMENT. Either omit tx.chainId entirely so ethers fills it from provider.getNetwork() (preferred), or verify it matches the active provider's chainId before calling: `const network = await signer.provider.getNetwork(); tx.chainId = network.chainId;`. Use isError(error, 'INVALID_ARGUMENT') and check error.argument === 'tx.chainId' to distinguish from other invalid-field rejections. Silent swallowing causes wrong-chain transaction attempts that fail at broadcast with cryptic "unknown chain" errors.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[26]
  • Signer.populateTransaction · populatetransaction-mixed-fee-fields
    error
    Whensigner.populateTransaction(tx) is called without a try-catch and tx mixes pre-EIP-1559 fee fields (gasPrice) with EIP-1559 fee fields (maxFeePerGas, maxPriorityFeePerGas) — or sets tx.type=0/1 alongside maxFeePerGas / maxPriorityFeePerGas. ethers raises INVALID_ARGUMENT with one of two distinct messages: "eip-1559 transaction do not support gasPrice" when gasPrice + (type=2 or any 1559 field) is present, or "pre-eip-1559 transaction do not support maxFeePerGas/maxPriorityFeePerGas" when type=0 or type=1 is set with a 1559 field. Both are common when copy-pasting tx params across legacy and modern chains, or when a UI lets the user toggle fee mode without clearing the other mode's fields.
    ThrowsEthersError with code INVALID_ARGUMENT and argument 'tx' (error.code === 'INVALID_ARGUMENT')
    Required handlingCaller MUST wrap signer.populateTransaction() in try-catch and handle INVALID_ARGUMENT. Either clear all fee fields and let ethers auto-detect (omit gasPrice, maxFeePerGas, maxPriorityFeePerGas, and type — preferred for cross-chain code), or explicitly pick one fee mode and clear the other: `delete tx.gasPrice; tx.type = 2;` for EIP-1559 chains, or `delete tx.maxFeePerGas; delete tx.maxPriorityFeePerGas; tx.type = 0;` for legacy chains. Use isError(error, 'INVALID_ARGUMENT') to detect.
    costhighin prodimmediate exceptionusers seelost transactionvisibilityvisible
    Sources[26][28]
  • Signer.populateTransaction · populatetransaction-network-fee-model-unsupported
    error
    Whensigner.populateTransaction(tx) is called without a try-catch on a network whose fee model does not match the requested transaction type. Two distinct UNSUPPORTED_OPERATION assertions fire here: (1) when tx.type is 0 or 1 (legacy) but provider.getFeeData() returns null gasPrice (an EIP-1559-only chain like post-Merge mainnet test fixtures), ethers throws "network does not support gasPrice" with operation='getGasPrice'; (2) when the tx requests EIP-1559 fee fields but provider.getFeeData() returns null maxFeePerGas (legacy chains like BNB Chain or older testnets), ethers throws "network does not support EIP-1559" with operation='populateTransaction'. Common when a multi-chain dApp assumes EIP-1559 is universal and ships a single tx-builder configured for type-2 transactions across all chains.
    ThrowsEthersError with code UNSUPPORTED_OPERATION (error.code === 'UNSUPPORTED_OPERATION', error.operation === 'getGasPrice' or 'populateTransaction')
    Required handlingCaller MUST wrap signer.populateTransaction() in try-catch and handle UNSUPPORTED_OPERATION. Branch on error.operation: 'getGasPrice' means retry with tx.type=2 and EIP-1559 fee fields; 'populateTransaction' means retry with tx.type=0 and gasPrice from provider.getFeeData(). Better, query provider.getFeeData() once at startup per chain and configure the tx-builder per chain's actual fee model rather than assuming EIP-1559. Use isError(error, 'UNSUPPORTED_OPERATION') to detect.
    costmediumin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[26][29]

Sources

Every postcondition cites at least one of these. Numbered to match the footnotes above.

  1. [1]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Provider-getBalance
  2. [2]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/utils/errors/
  3. [3]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Signer-sendTransaction
  4. [4]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Provider-estimateGas
  5. [5]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Provider-call
  6. [6]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Provider-broadcastTransaction
  7. [7]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/wallet/#Wallet-fromEncryptedJson
  8. [8]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/wallet/
  9. [9]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Provider-waitForTransaction
  10. [10]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Provider-getLogs
  11. [11]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/contract/#ContractFactory-deploy
  12. [12]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/contract/#BaseContract-waitForDeployment
  13. [13]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/contract/#BaseContract-queryFilter
  14. [14]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/wallet/#BaseWallet-signTypedData
  15. [15]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#BrowserProvider-getSigner
  16. [16]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/wallet/#Wallet-encrypt
  17. [17]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/jsonrpc/#JsonRpcProvider-getSigner
  18. [18]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/contract/
  19. [19]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/jsonrpc/#JsonRpcApiProvider-send
  20. [20]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/wallet/#BaseWallet-signTransaction
  21. [21]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/transaction/#Transaction
  22. [22]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/wallet/#BaseWallet-authorize
  23. [23]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Provider-getNetwork
  24. [24]eips.ethereum.org/EIPS/eip-7702https://eips.ethereum.org/EIPS/eip-7702
  25. [25]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/utils/#getAddress
  26. [26]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#AbstractSigner-populateTransaction
  27. [27]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/utils/errors/#UnsupportedOperationError
  28. [28]eips.ethereum.org/EIPS/eip-1559https://eips.ethereum.org/EIPS/eip-1559
  29. [29]docs.ethers.org/v6/apihttps://docs.ethers.org/v6/api/providers/#Provider-getFeeData
Need a different package?
Request a profile