FuelLabs/fuel-core · error

The fee address index is out of bounds

Error message

The fee address index is out of bounds

What it means

The fee_address_index argument selects which entry of required_balances pays gas for the assembled transaction. AssembleTx::new rejects the request when fee_index (a u16) is >= required_balances.len(), i.e. the index points outside the list you provided.

Source

Thrown at crates/fuel-core/src/schema/tx/assemble_tx.rs:191

{
    pub fn new(tx: Tx, mut arguments: AssembleArguments<'a>) -> anyhow::Result<Self> {
        let max_inputs = arguments.consensus_parameters.tx_params().max_inputs();
        let max_outputs = arguments.consensus_parameters.tx_params().max_outputs();

        if tx.inputs().len() > max_inputs as usize {
            return Err(anyhow::anyhow!(
                "The transaction has more inputs than allowed by the consensus"
            ));
        }

        if tx.outputs().len() > max_outputs as usize {
            return Err(anyhow::anyhow!(
                "The transaction has more outputs than allowed by the consensus"
            ));
        }

        if arguments.fee_index as usize >= arguments.required_balances.len() {
            return Err(anyhow::anyhow!("The fee address index is out of bounds"));
        }

        if has_duplicates(&arguments.required_balances, |balance| {
            (balance.asset_id, balance.account.owner())
        }) {
            return Err(anyhow::anyhow!(
                "required balances contain duplicate (asset, account) pair"
            ));
        }

        let base_asset_id = *arguments.consensus_parameters.base_asset_id();
        let mut signature_witness_indexes = HashMap::<Address, u16>::new();

        // Exclude inputs that already are used by the transaction
        let mut has_predicates = false;
        let inputs = tx.inputs();
        let mut unique_used_asset = HashSet::new();
        let mut set_contracts = HashSet::new();

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Set feeAddressIndex to the position of the account that should pay gas — usually 0 if the first required balance is the fee payer
  2. Ensure requiredBalances is non-empty and includes the fee-paying account
  3. Add a client-side assertion feeAddressIndex < requiredBalances.length before the mutation

Example fix

// before
await client.assembleTx(txBytes, { requiredBalances: balances, feeAddressIndex: 2 }); // balances.length === 1

// after
const feeAddressIndex = balances.findIndex((b) => b.account === FEE_PAYER);
if (feeAddressIndex < 0 || feeAddressIndex >= balances.length) throw new Error('bad feeAddressIndex');
await client.assembleTx(txBytes, { requiredBalances: balances, feeAddressIndex });
Defensive patterns

Strategy: validation

Validate before calling

function assertFeeIndex(requiredBalances: unknown[], feeAddressIndex: number) {
  if (requiredBalances.length === 0) throw new Error('requiredBalances must not be empty');
  if (!Number.isInteger(feeAddressIndex) || feeAddressIndex < 0 || feeAddressIndex >= requiredBalances.length) {
    throw new Error(`feeAddressIndex ${feeAddressIndex} out of range for ${requiredBalances.length} balances`);
  }
}

Type guard

function isValidFeeIndex(balances: unknown[], i: unknown): i is number {
  return typeof i === 'number' && i >= 0 && i < balances.length;
}

Try / catch

catch (e) { if (/fee address index is out of bounds/.test(e.message)) { /* fix index to 0 or the fee payer's position and retry */ } else throw e; }

Prevention

When it happens

Trigger: Calling assembleTransaction with feeAddressIndex >= requiredBalances.length — e.g. passing requiredBalances: [] while leaving a nonzero feeAddressIndex, or reordering/shrinking the balances array after choosing the index.

Common situations: Empty requiredBalances array (fee-only assembly should still include one entry for the fee account); off-by-one when building balances dynamically; copying an index constant between code paths with different balance lists.

Related errors


AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16). Data as JSON: /api/errors/5a813b33c0b8846a. Report an issue: GitHub.