FuelLabs/fuels-ts · error · FuelError

INVALID_TRANSFER_AMOUNT

INVALID_TRANSFER_AMOUNT

Error message

Transfer amount must be a positive number.

What it means

Thrown by Account.batchTransferToContracts (and therefore transferToContract) when a transfer amount is not greater than zero. The library rejects non-positive amounts so the Fuel VM never receives a value-less coin transfer to a contract, which would waste gas and produce a useless transaction. It is a hard precondition on every contract-bound transfer this method assembles.

Source

Thrown at packages/account/src/account.ts:606

    txParams: TxParamsType = {},
    { skipAutoConsolidation }: ShouldConsolidateCoinsParams = {}
  ): Promise<TransactionResponse> {
    let request = new ScriptTransactionRequest({
      ...txParams,
    });

    const quantities: CoinQuantity[] = [];

    const defaultAssetId = await this.provider.getBaseAssetId();

    const transferParams = contractTransferParams.map((transferParam) => {
      const amount = bn(transferParam.amount);
      const contractAddress = new Address(transferParam.contractId);

      const assetId = transferParam.assetId ? hexlify(transferParam.assetId) : defaultAssetId;

      if (amount.lte(0)) {
        throw new FuelError(
          ErrorCode.INVALID_TRANSFER_AMOUNT,
          'Transfer amount must be a positive number.'
        );
      }

      request.addContractInputAndOutput(contractAddress);
      quantities.push({ amount, assetId });

      return {
        amount,
        contractId: contractAddress.toB256(),
        assetId,
      };
    });

    const { script, scriptData } = await assembleTransferToContractScript(transferParams);

    request.script = script;

View on GitHub (pinned to b3f37c91ac)

Solutions

  1. Confirm the amount is strictly greater than zero before calling transferToContract/batchTransferToContracts, e.g. if (bn(amount).gt(0)) { ... } else { /* skip or notify */ }.
  2. If the amount is derived (balance - fee - reserved), recompute it and short-circuit the transfer path when it collapses to <= 0 instead of forwarding the bad value.
  3. Validate user-facing input upstream and surface a form error rather than letting the SDK throw at submit time.

Example fix

// before
await account.transferToContract(contractId, balance.minus(fee), assetId);

// after
const amount = bn(balance).sub(fee);
if (amount.lte(0)) throw new Error('Nothing left to transfer after fees');
await account.transferToContract(contractId, amount, assetId);
Defensive patterns

Strategy: validation

Validate before calling

import { bn } from 'fuels';

function assertPositiveAmount(amount: unknown): void {
  const value = bn(amount as any);
  if (!value.gt(0)) {
    throw new Error(`Transfer amount must be > 0, got ${amount}`);
  }
}

// before transferToContract / batchTransferToContracts:
assertPositiveAmount(amount);

Type guard

function isPositiveAmount(amount: unknown): amount is string | number | bigint {
  try { return bn(amount as any).gt(0); } catch { return false; }
}

Try / catch

try {
  await account.transferToContract(contractId, amount, assetId);
} catch (e) {
  if (e instanceof FuelError && e.code === ErrorCode.INVALID_TRANSFER_AMOUNT) {
    // surface user-facing 'enter a positive amount' error
  } else throw e;
}

Prevention

When it happens

Trigger: Calling account.transferToContract(contractId, amount, assetId) or account.batchTransferToContracts(params) where amount <= 0, amount is NaN (e.g. bn('abc')), amount is a numeric string '0' or '-5', or amount is undefined/null (bn coerces to 0).

Common situations: Passing a variable balance that happens to be zero (e.g. transferring the entire balance of an asset you do not hold), computing amount = balance.minus(fee) without guarding against negative results, sending amount as a string with a typo, or copy-pasting a test value of 0.

Related errors


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