{"record":{"id":"49ef3bb30d27abd1","repo":"unionlabs/union","slug":"failed-to-deploy-contract","errorCode":null,"errorMessage":"Failed to deploy contract: {:?}","messagePattern":"Failed to deploy contract: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"tools/union-test/src/evm.rs","lineNumber":708,"sourceCode":"            let pending = call.send().await;\n            match pending {\n                Ok(pending) => {\n                    let tx_hash = *pending.tx_hash();\n                    self.wait_for_tx_inclusion(&provider, tx_hash.into())\n                        .await?;\n                    let receipt = pending.get_receipt().await?;\n\n                    let address = receipt\n                        .contract_address\n                        .expect(\"deploy didnt return an address\");\n                    return Ok(address.into());\n                }\n                Err(err) if attempts <= 5 && self.is_nonce_too_low(&err) => {\n                    tokio::time::sleep(Duration::from_secs(10)).await;\n                    continue;\n                }\n                Err(err) => {\n                    return Err(anyhow::anyhow!(\"Failed to deploy contract: {:?}\", err));\n                }\n            }\n        }\n    }\n\n    pub async fn send_ibc_transaction(\n        &self,\n        msg: RawCallBuilder<DynProvider<AnyNetwork>, AnyNetwork>,\n    ) -> RpcResult<(FixedBytes<32>, u64)> {\n        let res = self\n            .keyring\n            .with({\n                let msg = msg.clone();\n                move |wallet| -> _ { AssertUnwindSafe(self.submit_transaction(wallet, msg)) }\n            })\n            .await;\n\n        match res {","sourceCodeStart":690,"sourceCodeEnd":726,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/tools/union-test/src/evm.rs#L690-L726","documentation":"`deploy_basic_erc20` broadcasts a raw deploy via `RawCallBuilder`; nonce-too-low errors are retried up to 5 times with 10s sleeps, and any other error — or a nonce error persisting past the retries — is reported as 'Failed to deploy contract' with the provider error attached via `{:?}`.","triggerScenarios":"Gas estimation fails or the broadcast is rejected: deployer out of funds; gas price above the configured maximum; node rejecting the tx (mempool/nonce issues); invalid constructor args appended to the bytecode; nonce remaining too-low for >~50s because the account's on-node nonce is far ahead.","commonSituations":"Test wallets unfunded on the target chain; shared devnet where the same key is used elsewhere, advancing its nonce; max_gas_price too low during gas spikes; malformed constructor encoding.","solutions":["Read the attached provider error — it names the real cause (insufficient funds, gas price, nonce, estimation revert)","Fund the deployer address and retry","If nonce-related, let in-flight txs settle or resync the account nonce on the node","Raise gas limits / max_gas_price if estimation or pricing is the cause"],"exampleFix":"// before: deploy immediately and hope\nlet erc20 = evm.deploy_basic_erc20(spender, provider.clone()).await?; \n// after: verify deployer funds first\nlet deployer = evm.keyring.first_address();\nlet bal = provider.get_balance(deployer).latest().await?;\nanyhow::ensure!(bal > alloy::primitives::U256::from(10_000_000_000_000_000u128), \"deployer underfunded\");\nlet erc20 = evm.deploy_basic_erc20(spender, provider.clone()).await?;","handlingStrategy":"try-catch","validationCode":"// pre-flight: deployer is funded\nlet deployer = evm.keyring.keys.iter().next().unwrap().address;\nlet bal = provider.get_balance(deployer.into()).latest().await?;\nanyhow::ensure!(!bal.is_zero(), \"deployer {deployer} has no funds\");","typeGuard":null,"tryCatchPattern":"match evm.deploy_basic_erc20(spender, provider.clone()).await {\n    Ok(addr) => Ok(addr),\n    Err(e) => {\n        let msg = format!(\"{e:#}\");\n        if msg.contains(\"insufficient funds\") { /* fund and retry once */ }\n        else { return Err(e); }\n    }\n}","preventionTips":["Fund deployer accounts as an explicit setup step with a balance assertion","Don't share the deployer key across processes that advance its nonce","Set gas parameters appropriate for the target network before deploying"],"tags":["rust","evm","deploy","gas","nonce"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}