Max fee per gas less than block base fee: cause and fix

Rejected before the chain. The node refuses it: no transaction hash, no receipt.

3 min read· Updated

Short answer

Every block has a base fee per gas, and the max fee you set (maxFeePerGas) has to be at least that. If it is lower, the node refuses the transaction before it reaches a block. Do not hardcode the fee: ask the client to estimate it, and leave room above the base fee, which can rise by up to 12.5% from one block to the next.

What you will see

Messages printed for it:

  • max fee per gas less than block base fee
  • The fee cap (`maxFeePerGas` = 0.999999999 gwei) cannot be lower than the block base fee.
On this page

Where does it stop?

A transaction's path from your code to the node, the mempool, a block and a receipt. The node's check is marked in red with the error max fee per gas below the base fee, and the later steps are dashed: no hash and no receipt.A transaction's path from your code to the node, the mempool, a block and a receipt. The node's check is marked in red with the error max fee per gas below the base fee, and the later steps are dashed: no hash and no receipt.

The node compares your fee cap with the base fee of the block. If the cap is lower, the transaction is refused at once. There is no hash, nothing reaches a block, and no gas is spent. If the base fee rises only after a transaction was accepted, it is not refused: it waits, and looks stuck pending.

What must the cap clear?

EIP-1559 says a transaction must be willing to pay at least the base fee: max_fee_per_gas has to be greater than or equal to the block’s base_fee_per_gas. The cap is the most you are willing to pay per gas, and the base fee moves with every block.

A scale of maxFeePerGas in gwei. A cap of 0.999999999, one wei under the base fee of 1 gwei, is refused. A cap of 2.0, twice the base fee, is accepted, and viem's own estimate of 2.2 gwei is base fee times 1.2 plus a 1 gwei tip.A scale of maxFeePerGas in gwei. A cap of 0.999999999, one wei under the base fee of 1 gwei, is refused. A cap of 2.0, twice the base fee, is accepted, and viem's own estimate of 2.2 gwei is base fee times 1.2 plus a 1 gwei tip.

The base fee can rise by up to 12.5% from one block to the next, so a cap that only just clears it can be too low a few blocks later. A cap of 1.2 times the base fee covers about one block of the largest rise.

Why does it happen?

  • A hardcoded fee. The number was right on the day you wrote it. The base fee has moved since.
  • A unit slip. maxFeePerGas: 2n is 2 wei, not 2 gwei. The number looks small and sensible and is far below any base fee.
  • A number nobody checked. A fee that comes from a config file or from a model’s tool argument is not compared with the chain.
  • Settings from another chain. A cap copied from a chain with a cheaper base fee.

How do I fix it?

  1. Leave the fee out and let the client choose. With a local account, viem estimates the fees when you do not give them.
  2. If you must set it, derive it from the chain, and keep the units straight:
import { createPublicClient, createWalletClient, http, parseGwei } from 'viem';
import { mainnet } from 'viem/chains';
declare const account: `0x${string}`;
const publicClient = createPublicClient({ chain: mainnet, transport: http() });
const wallet = createWalletClient({ account, chain: mainnet, transport: http() });
// Ask the client for a fee that fits the chain now, instead of writing a number.
const { maxFeePerGas, maxPriorityFeePerGas } = await publicClient.estimateFeesPerGas();
await wallet.sendTransaction({ to: account, value: 1n, maxFeePerGas, maxPriorityFeePerGas });
// Units: parseGwei('2') is 2 gwei. A bare 2n is 2 wei, far below any base fee.
const twoGwei = parseGwei('2');
  1. If your agent or tool takes a fee as an argument, check it before sending: compare it with the current base fee and return a clear message instead of the raw error.

What does it look like in a trace?

Like every refusal by the node, it is a send span that ends with an error and no transaction hash:

send 31337error
error.type
FeeCapTooLowError
exception.message
The fee cap (`maxFeePerGas` = 0.999999999 gwei) cannot be lower than the block base fee.
blockchain.tx.hash
not set
From the run above. exception.message appears only with errorMessages set to sanitized.

By default only the error type is recorded, and for this refusal it is FeeCapTooLowError. Nonce too low shows how to read the node’s wording too. The part of a fee that is not the base fee, the L1 data fee, is explained in what is the L1 data fee.

How this page was checked. Reproduced on a local Anvil chain (31337, base fee 1 gwei) with viem 2.57.2 and @hashspan/viem 1.1.0 on 2026-10-07: a cap one wei below the base fee was refused, a cap of twice the base fee was mined. The first line is the node's text on Anvil, the second is viem's own message (FeeCapTooLowError). The gwei figure in it is the cap you sent.

FAQ

What is the base fee?

The price per gas that every transaction in a block has to pay at least. The protocol sets it from how full the previous block was: it goes up when blocks are above the target and down when they are below, by at most 1/8 (12.5%) from one block to the next (EIP-1559).

Is this the same error as "transaction underpriced"?

No. geth's ErrUnderpriced is returned when a transaction's gas price is too low to be included in the pool, a different check. This page is about the cap being below the block's base fee. We did not reproduce "transaction underpriced" here.

What fee does viem use when I leave it out?

It estimates one: the base fee times 1.2 (the default baseFeeMultiplier) plus a priority fee. On our Anvil run the base fee was 1 gwei and the estimate was 2.2 gwei with a 1 gwei tip.

See it in your own trace

Type to search the docs, Learn topics and the blog.