ethereum/go-ethereum · error

invalid chainID %v

Error message

invalid chainID %v

What it means

newModernSigner constructs the modern EIP-2718 signer and requires a positive chain ID. A nil or non-positive chain ID cannot be used for EIP-155 replay protection or for signing any typed transaction envelope, so the constructor panics immediately rather than producing a broken signer.

Source

Thrown at core/types/transaction_signing.go:206

}

// txtypeSet is a bitmap for transaction types.
type txtypeSet [2]uint64

func (v *txtypeSet) set(txType byte) {
	v[txType/64] |= 1 << (txType % 64)
}

func (v *txtypeSet) has(txType byte) bool {
	if txType >= byte(len(v)*64) {
		return false
	}
	return v[txType/64]&(1<<(txType%64)) != 0
}

func newModernSigner(chainID *big.Int, fork forks.Fork) Signer {
	if chainID == nil || chainID.Sign() <= 0 {
		panic(fmt.Sprintf("invalid chainID %v", chainID))
	}
	s := &modernSigner{
		chainID: chainID,
	}
	// configure legacy signer
	switch {
	case fork >= forks.SpuriousDragon:
		s.legacy = NewEIP155Signer(chainID)
	case fork >= forks.Homestead:
		s.legacy = HomesteadSigner{}
	default:
		s.legacy = FrontierSigner{}
	}
	s.txtypes.set(LegacyTxType)
	// configure tx types
	if fork >= forks.Berlin {
		s.txtypes.set(AccessListTxType)
	}

View on GitHub (pinned to 6bb0588ad8)

Solutions

  1. Pass a strictly positive chain ID, e.g. big.NewInt(1337), when constructing the signer.
  2. Check the genesis/config: ensure 'chainId' in chainConfig is >= 1 and is loaded before the signer is created.
  3. Guard call sites with a nil/zero check and fail with a clear error instead of letting the library panic.

Example fix

// before
signer := types.LatestSignerForChainID(nil) // panics

// after
chainID := big.NewInt(1)
if cfg.ChainID != nil && cfg.ChainID.Sign() > 0 {
    chainID = cfg.ChainID
}
signer := types.LatestSignerForChainID(chainID)
Defensive patterns

Strategy: validation

Validate before calling

func validChainID(id *big.Int) bool {
    return id != nil && id.Sign() > 0
}

// use before constructing the signer
if !validChainID(cfg.ChainID) {
    return fmt.Errorf("chain id must be positive, got %v", cfg.ChainID)
}
signer := types.LatestSignerForChainID(cfg.ChainID)

Try / catch

Not applicable — validate the chain ID before the call; recovering from this panic would leave you without a valid signer anyway.

Prevention

When it happens

Trigger: Calling types.NewModernSigner (or a wrapper such as LatestSignerForChainID / MakeSigner with a config whose ChainID is nil or <= 0); e.g. chainID = big.NewInt(0) or a nil *big.Int from an uninitialized chain config.

Common situations: Private/dev chains mistakenly configured with chain ID 0; code that reads ChainConfig.ChainID before the genesis is loaded and passes nil; tooling that derives the signer from a user-supplied --chainid flag defaulting to 0.

Related errors


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