Why Do Tests Pass on Hardhat/Anvil Forks but Break on Mainnet? What Hidden Differences Are We Missing?
I’ve hit this pain point so many times that I genuinely stopped trusting “all tests passing” unless I run them against a real mainnet RPC.
Here’s the pattern: everything works fine on Hardhat/Anvil forks — clean state, predictable gas, zero RPC jitter, instant block confirmations. But the moment the contract hits mainnet, random behaviours start appearing: timestamp drift breaking vesting logic, oracle updates arriving out of sync, state bloat pushing gas beyond estimates, or signatures behaving differently because the chain ID isn’t mocked properly.
My suspicion is that local forks hide too much real-chain noise. They’re great for dev speed, but they don’t reflect the messy, evolving, unpredictable nature of actual networks.
I want to hear from people who’ve debugged real production issues:
Which subtle fork-vs-mainnet differences burned you the most?
Was it mempool congestion? Different gas spikes? Reentrancy paths behaving differently? State residue? Block builder differences? RPC provider inconsistencies?
Also — how do you mitigate this?
Do you run linear tests without snapshots? Replay entire transaction batches? Mock network variables? Fork from the latest block? Use multiple RPCs?