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

> The fee cap you set is below the block's base fee, so the node refuses it. See what the cap must clear, why hardcoded fees and unit slips cause it, and the fix.

Source: https://hashspan.dev/errors/max-fee-per-gas-less-than-block-base-fee

## 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

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

## Where does it stop?

Figure: 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](https://hashspan.dev/errors/transaction-stuck-pending).

## What must the cap clear?

[EIP-1559](https://eips.ethereum.org/EIPS/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.

Figure: 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:

```ts

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');
```

3. **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:

<AttributeCard
span="send 31337"
status="bad"
rows={[
['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'],
]}
caption="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](https://hashspan.dev/errors/nonce-too-low#what-does-it-look-like-in-a-trace) 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](https://hashspan.dev/learn/l1-data-fee).

## 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.
