10、Troubleshooting
Common issues and their solutions when working with Foundry.
Compilation Issues
Issue: "Compiler version not found"
Problem:
Error: Compiler version 0.8.20 not found
Solution:
# Update Foundry
foundryup
# Or specify a different version in foundry.toml
[profile.default]
solc = "0.8.19"
Issue: "Stack too deep"
Problem:
CompilerError: Stack too deep
Solutions:
// Solution 1: Use fewer local variables
function problematic() public {
uint a = 1;
uint b = 2;
// ... many more variables
}
// Better: Use structs
struct Params {
uint a;
uint b;
// ...
}
function better() public {
Params memory params;
params.a = 1;
params.b = 2;
}
// Solution 2: Enable via-ir in foundry.toml
[profile.default]
via_ir = true
Issue: "Out of memory during compilation"
Problem:
Error: Out of memory
Solution:
# foundry.toml
[profile.default]
optimizer_runs = 200 # Reduce from higher value
via_ir = false
Test Execution Issues
Issue: "Test passes locally but fails in CI"
Problem: Tests pass on your machine but fail in CI.
Solutions:
# 1. Use consistent random seed
forge test --seed 12345
# 2. Check for timestamp dependencies
# Use vm.warp() to set consistent timestamps
# 3. Check for network dependencies
# Use forge test --fork-url instead of relying on local state
Issue: "Expected revert not triggered"
Problem:
function test_ShouldRevert() public {
vm.expectRevert("Error message");
myContract.someFunction(); // Doesn't revert
}
Solutions:
// Solution 1: Check the exact error message
vm.expectRevert("Exact error message");
// Solution 2: Use custom error selector
vm.expectRevert(MyContract.CustomError.selector);
// Solution 3: Check if condition is met
vm.expectRevert(); // Any revert
Issue: "Gas estimation failed"
Problem:
Error: Gas estimation failed
Solutions:
# 1. Increase gas limit
forge test --gas-limit 30000000
# 2. Check for infinite loops
forge test -vvvv # See trace
# 3. Check for reverts in constructor
Fuzzing Issues
Issue: "Too many rejects in fuzzing"
Problem:
Warning: Fuzzing test rejected too many inputs
Solutions:
// ❌ Bad: Uses vm.assume() too much
function testFuzz_Bad(uint256 x) public {
vm.assume(x > 100);
vm.assume(x < 1000);
vm.assume(x % 2 == 0);
}
// ✅ Good: Use bound()
function testFuzz_Good(uint256 x) public {
x = bound(x, 100, 1000);
if (x % 2 != 0) x++; // Adjust instead of reject
}
Issue: "Invariant test fails inconsistently"
Problem: Invariant tests pass sometimes, fail other times.
Solutions:
// 1. Add better constraints in handler
function mint(uint256 amount) public {
amount = bound(amount, 0, MAX_MINT);
// ...
}
// 2. Increase runs for consistency
// foundry.toml
[invariant]
runs = 1000
depth = 50
// 3. Track ghost variables
uint256 public ghost_sumOfBalances;
Fork Testing Issues
Issue: "RPC rate limit exceeded"
Problem:
Error: Rate limit exceeded
Solutions:
# 1. Use archive node or paid RPC
export MAINNET_RPC_URL="https://eth-mainnet.g.alchemy.com/v2/YOUR-KEY"
# 2. Cache fork state
# Anvil will cache requests
# 3. Fork at specific block
forge test --fork-url $RPC --fork-block-number 18000000
Issue: "Fork tests are slow"
Problem: Fork tests take a long time to run.
Solutions:
# 1. Use local Anvil fork
anvil --fork-url $MAINNET_RPC_URL &
forge test --fork-url http://localhost:8545
# 2. Run fork tests separately
forge test --no-match-path "test/fork/**"
# 3. Use specific block number (cached by RPC)
forge test --fork-block-number 18000000
Dependency Issues
Issue: "Library not found"
Problem:
Error: Library not found
Solutions:
# 1. Install the dependency
forge install OpenZeppelin/openzeppelin-contracts
# 2. Update dependencies
forge update
# 3. Check remappings
# remappings.txt
@openzeppelin/=lib/openzeppelin-contracts/
Issue: "Git submodule issues"
Problem:
Error: Submodule not initialized
Solutions:
# Initialize submodules
git submodule update --init --recursive
# Or clone with submodules
git clone --recursive <repo-url>
Debugging Issues
Issue: "Cannot see console.log output"
Problem:
console.log() doesn't show output.
Solutions:
# Use correct verbosity
forge test -vv # Shows logs for all tests
# Or
forge test -v # Shows logs only for failing tests
Issue: "Stack trace is unclear"
Problem: Can't understand the error from stack trace.
Solutions:
# 1. Use maximum verbosity
forge test -vvvvv
# 2. Use debug mode
forge test --debug test_FunctionName
# 3. Add more console.log statements
console.log("Checkpoint 1");
console.log("Value:", value);
Coverage Issues
Issue: "Coverage report is inaccurate"
Problem: Coverage report shows incorrect numbers.
Solutions:
# 1. Clean and rebuild
forge clean
forge coverage
# 2. Exclude test files
forge coverage --report lcov --no-match-path "test/**"
# 3. Update Foundry
foundryup
Performance Issues
Issue: "Tests are too slow"
Problem: Test suite takes too long to run.
Solutions:
# 1. Run tests in parallel (default)
forge test
# 2. Run specific tests
forge test --match-test test_Fast
# 3. Reduce fuzz runs for CI
# foundry.toml
[profile.ci.fuzz]
runs = 100
Issue: "Out of memory during tests"
Problem:
Error: Out of memory
Solutions:
// 1. Clean up state between tests
function setUp() public {
// Fresh state for each test
}
// 2. Don't create too many contracts
// Reuse contracts when possible
// 3. Reduce fuzz runs
[fuzz]
runs = 256 # Instead of 10000
Cheatcode Issues
Issue: "vm.prank not working"
Problem:
vm.prank(alice);
// Multiple calls here - only first is pranked!
myContract.call1();
myContract.call2(); // Not pranked
Solutions:
// Solution 1: Use startPrank/stopPrank
vm.startPrank(alice);
myContract.call1();
myContract.call2();
vm.stopPrank();
// Solution 2: Multiple pranks
vm.prank(alice);
myContract.call1();
vm.prank(alice);
myContract.call2();
Issue: "vm.expectRevert not catching"
Problem:
vm.expectRevert("Error");
myContract.noRevert(); // Doesn't revert but test passes
Solutions:
// vm.expectRevert only affects the NEXT call
vm.expectRevert("Error");
myContract.willRevert(); // Must be immediately after
// For internal calls, they're not caught
// Must test external calls only
Common Error Messages
"EvmError: Revert"
Meaning: Transaction reverted without message.
Debug:
forge test -vvvvv # See full trace
"EvmError: OutOfGas"
Meaning: Transaction ran out of gas.
Fix:
// Check for infinite loops or very expensive operations
"EvmError: InvalidOpcode"
Meaning: Invalid EVM instruction.
Fix:
# Usually a compiler issue
foundryup # Update Foundry
forge clean && forge build
Best Practices to Avoid Issues
- Keep Foundry updated:
foundryupregularly - Use consistent versions: Lock solc version in
foundry.toml - Clean build often:
forge cleanwhen things act weird - Use appropriate verbosity:
-vvfor most debugging - Bound fuzz inputs: Use
bound()instead ofvm.assume() - Test in CI: Catch environment-specific issues
- Use gas snapshots: Track performance regressions
- Profile slow tests: Find and optimize bottlenecks
Getting Help
Check Documentation
# Forge help
forge --help
forge test --help
# Foundry Book
https://book.getfoundry.sh
Community Support
Debug Checklist
- Updated Foundry to latest version?
- Cleaned build artifacts?
- Checked test with
-vvvvv? - Tried on a fresh clone?
- Checked for environment differences?
- Reviewed recent Foundry changelogs?
Next Steps
- Cheatcodes Reference - Complete cheatcodes guide
- Foundry Book - Official documentation