FuelLabs/fuels-ts · error · FuelError
MAX_FEE_TOO_LOW
MAX_FEE_TOO_LOW
Error message
Max fee '${setMaxFee}' is lower than the required: '${requiredMaxFee}'. What it means
Thrown by setAndValidateGasAndFeeForAssembledTx when the caller-supplied setMaxFee is less than transactionRequest.maxFee (the minimum required max fee computed from gas limit, gas price, and byte size). maxFee is the user-declared ceiling the chain enforces; setting it below the required amount guarantees the tx would be rejected, so the SDK fails fast.
Source
Thrown at packages/account/src/providers/assemble-tx-helpers.ts:84
const maxFeeSpecified = isDefined(setMaxFee);
const isScriptTx = transactionRequest.type === TransactionType.Script;
if (gasLimitSpecified && isScriptTx) {
const requiredGasLimit = transactionRequest.gasLimit;
if (bn(setGasLimit).lt(bn(requiredGasLimit))) {
throw new FuelError(
ErrorCode.GAS_LIMIT_TOO_LOW,
`Gas limit '${setGasLimit}' is lower than the required: '${requiredGasLimit}'.`
);
}
transactionRequest.gasLimit = bn(setGasLimit);
}
if (maxFeeSpecified) {
const requiredMaxFee = transactionRequest.maxFee;
if (bn(setMaxFee).lt(requiredMaxFee)) {
throw new FuelError(
ErrorCode.MAX_FEE_TOO_LOW,
`Max fee '${setMaxFee}' is lower than the required: '${requiredMaxFee}'.`
);
}
transactionRequest.maxFee = bn(setMaxFee);
}
if (gasLimitSpecified && !maxFeeSpecified) {
const { maxFee: feeForGasPrice } = await provider.estimateTxGasAndFee({
transactionRequest,
gasPrice,
});
transactionRequest.maxFee = feeForGasPrice;
}
return transactionRequest;View on GitHub (pinned to b3f37c91ac)
Solutions
- Omit setMaxFee so the SDK derives it from the current estimate.
- Read transactionRequest.maxFee after estimation and pass setMaxFee >= it.
- Re-estimate with provider.estimateTxGasAndFee before specifying setMaxFee.
- Add a margin to absorb gas-price variance: bn(requiredMaxFee).mul(12).div(10).
Example fix
// before
await account.assembleTx({ transactionRequest, setMaxFee: 1 });
// after
const { maxFee } = await provider.estimateTxGasAndFee({ transactionRequest, gasPrice });
await account.assembleTx({
transactionRequest,
setMaxFee: bn(maxFee).mul(12).div(10), // >= required
}); Defensive patterns
Strategy: validation
Validate before calling
import { bn } from '@fuel-ts/math';
function validateMaxFee(setMaxFee, requiredMaxFee) {
if (bn(setMaxFee).lt(requiredMaxFee)) {
throw new Error(`Max fee must be >= ${requiredMaxFee.toString()}`);
}
} Type guard
function maxFeeIsSufficient(setMaxFee, requiredMaxFee): boolean {
return bn(setMaxFee).gte(bn(requiredMaxFee));
} Try / catch
import { FuelError, ErrorCode } from '@fuel-ts/errors';
try {
await account.assembleTx({ transactionRequest, setMaxFee });
} catch (e) {
if (e instanceof FuelError && e.code === ErrorCode.MAX_FEE_TOO_LOW) {
// bump setMaxFee to >= requiredMaxFee or omit it
}
throw e;
} Prevention
- Re-estimate fees right before submission (gas price changes).
- Add a margin to maxFee to absorb gas-price variance.
- Prefer omitting setMaxFee unless you need a hard ceiling.
When it happens
Trigger: Passing setMaxFee below the estimated max fee when assembling/sending a transaction; setting a fixed low fee after gas-price spikes; computing max fee without including the byte/gas-price component.
Common situations: Hardcoding maxFee from a previous network state; gas price rose between estimation and submission; migrating to an SDK version that began enforcing the floor; underestimating fee for a large script tx.
Related errors
AI-assisted analysis of FuelLabs/fuels-ts@b3f37c91ac (2026-08-12).
Data as JSON: /api/errors/26c9af9aab902cda.
Report an issue: GitHub.