FuelLabs/fuels-ts · error · FuelError

TRANSACTION_ERROR

TRANSACTION_ERROR

Error message

Transaction's gasLimit must be equal to or greater than the combined forwarded gas of all calls.

What it means

Thrown by checkGasLimitTotal during transaction preparation when the sum of per-call forwarded gas across all calls in a multicall exceeds the transaction's top-level gasLimit. Each call reserves `call.gas` units forwarded into the script; the request must carry at least that much total gas or execution cannot satisfy all forwarding budgets.

Source

Thrown at packages/program/src/functions/base-invocation-scope.ts:234

    // Check if gasLimit is less than the
    // sum of all call gasLimits
    this.checkGasLimitTotal();

    if (this.transactionRequest.type === TransactionType.Script) {
      this.transactionRequest.abis = getAbisFromAllCalls(this.functionInvocationScopes);
    }
  }

  /**
   * Checks if the total gas limit is within the acceptable range.
   */
  protected checkGasLimitTotal() {
    const gasLimitOnCalls = this.calls.reduce((total, call) => total.add(call.gas || 0), bn(0));

    if (this.transactionRequest.gasLimit.eq(0)) {
      this.transactionRequest.gasLimit = gasLimitOnCalls;
    } else if (gasLimitOnCalls.gt(this.transactionRequest.gasLimit)) {
      throw new FuelError(
        ErrorCode.TRANSACTION_ERROR,
        "Transaction's gasLimit must be equal to or greater than the combined forwarded gas of all calls."
      );
    }
  }

  /**
   * Gets the transaction cost for dry running the transaction.
   *
   * @returns The transaction cost details.
   *
   * @deprecated Use contract.fundWithRequiredCoins instead
   * Check the migration guide https://docs.fuel.network/docs/fuels-ts/transactions/assemble-tx-migration-guide/ for more information.
   */
  async getTransactionCost(): Promise<TransactionCost> {
    const request = clone(await this.getTransactionRequest());
    const account: AbstractAccount =
      this.program.account ?? Wallet.generate({ provider: this.getProvider() });

View on GitHub (pinned to b3f37c91ac)

Solutions

  1. Leave transactionRequest.gasLimit at 0 so the SDK auto-sets it to the sum of per-call gas.
  2. Or raise gasLimit to at least the total forwarded gas.
  3. Reduce the per-call `gas` values if the total is genuinely too high.
  4. Compute the sum of call.gas and set gasLimit accordingly before preparing the tx.

Example fix

// before
const scope = contract.functions.foo().addArgs(...);
scope.txParameters.gasLimit = bn(1000); // too low
// after — let the SDK sum forwarded gas
scope.txParameters.gasLimit = bn(0);
// or set it high enough
const total = scope.calls.reduce((t, c) => t.add(c.gas || 0), bn(0));
scope.txParameters.gasLimit = total;
Defensive patterns

Strategy: validation

Validate before calling

import { bn } from '@fuel-ts/math';
function ensureGasLimitCoversCalls(scope: any): void {
  const total = scope.calls.reduce((t: any, c: any) => t.add(c.gas || 0), bn(0));
  if (scope.transactionRequest.gasLimit.gt(0) && total.gt(scope.transactionRequest.gasLimit)) {
    throw new Error(`gasLimit ${scope.transactionRequest.gasLimit} < forwarded ${total}`);
  }
}

Type guard

const gasLimitCoversCalls = (gasLimit: import('@fuel-ts/math').BN, calls: { gas?: number }[]): boolean => {
  const total = calls.reduce((t, c) => t.add(c.gas || 0), bn(0));
  return gasLimit.eq(0) || !total.gt(gasLimit);
};

Prevention

When it happens

Trigger: Building a multicall where individual calls have `gas` set and you also set `tx.gasLimit` to a value below their sum; or programmatically lowering gasLimit after setting per-call gas.

Common situations: Manually capping gasLimit to save fees below what the calls need, mixing per-call gas overrides with a global cap, migrating a config that sets a low gasLimit.

Related errors


AI-assisted analysis of FuelLabs/fuels-ts@b3f37c91ac (2026-08-12). Data as JSON: /api/errors/8cd59080d4bc0df4. Report an issue: GitHub.