ethereum/go-ethereum · critical

eip2929 and eip4762 are both activated

Error message

eip2929 and eip4762 are both activated

What it means

StateDB.Prepare panics when the chain rules activate both EIP-2929 (Berlin access lists) and EIP-4762 (Prague/Verkle gas accounting) at the same time. These two EIPs define incompatible ways to charge gas for account/storage access, so the state transition logic cannot honor both. The panic is a hard configuration invariant check executed while preparing state for every transaction.

Source

Thrown at core/state/statedb.go:1497

	return ret.Root, ret, nil
}

// Prepare handles the preparatory steps for executing a state transition with.
// This method must be invoked before state transition.
//
// Berlin fork:
// - Add sender to access list (2929)
// - Add destination to access list (2929)
// - Add precompiles to access list (2929)
// - Add the contents of the optional tx access list (2930)
//
// Potential EIPs:
// - Reset access list (Berlin)
// - Add coinbase to access list (EIP-3651)
// - Reset transient storage (EIP-1153)
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
	if rules.IsEIP2929 && rules.IsEIP4762 {
		panic("eip2929 and eip4762 are both activated")
	}
	if rules.IsEIP2929 {
		// Clear out any leftover from previous executions
		al := newAccessList()
		s.accessList = al

		al.AddAddress(sender)
		if dst != nil {
			al.AddAddress(*dst)
			// If it's a create-tx, the destination will be added inside evm.create
		}
		for _, addr := range precompiles {
			al.AddAddress(addr)
		}
		for _, el := range list {
			al.AddAddress(el.Address)
			for _, key := range el.StorageKeys {
				al.AddSlot(el.Address, key)

View on GitHub (pinned to 6bb0588ad8)

Solutions

  1. Edit the genesis/chain config and remove or postpone the Verkle (EIP-4762) fork activation so it is not active alongside Berlin.
  2. If Verkle was never intended, regenerate the genesis with only the standard forks (Berlin through Prague) enabled.
  3. Re-init the datadir with the corrected genesis (geth init) so the stored config no longer has both EIPs active.
  4. If you intentionally need Verkle rules, use a build/branch where the state transition supports EIP-4762 semantics without the 2929 path.

Example fix

// before (genesis.json fragment)
"eip4762Block": 0,
"berlinBlock": 0

// after
"berlinBlock": 0
// eip4762Block removed or set to a fork schedule the client supports
Defensive patterns

Strategy: validation

Validate before calling

// before building the chain, reject configs activating both EIPs
func validateConfig(cfg *params.ChainConfig) error {
    // evaluate rules at the relevant fork time; 2929 is active from Berlin
    if cfg.IsBerlin(big.NewInt(0)) && verkleActive(cfg) {
        return errors.New("EIP-2929 and EIP-4762 must not both be active")
    }
    return nil
}

Try / catch

Go panic: wrap node startup / block processing in a defer with recover() only at the top-level goroutine boundary to log the config error, then exit — do not swallow and continue, consensus state is invalid.

Prevention

When it happens

Trigger: Running a chain whose params.ChainConfig (genesis config) enables both the Berlin fork and the Verkle/EIP-4762 fork for the same block time, then executing or importing any block/transaction (Prepare is called per transaction from the state processor).

Common situations: Custom chain configs that copy mainnet fork settings and then also set a Verkle fork time; misconfigured dev/test genesis that flips on verkle-related fork fields; upgrading geth versions where an experimental Verkle fork block was previously ignored and now becomes active.

Related errors


AI-assisted analysis of ethereum/go-ethereum@6bb0588ad8 (2026-08-15). Data as JSON: /api/errors/14c424f078e22b1a. Report an issue: GitHub.