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
- Confirm the amount is strictly greater than zero before calling transferToContract/batchTransferToContracts, e.g. if (bn(amount).gt(0)) { ... } else { /* skip or notify */ }.
- 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.
- 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
- Compute amounts defensively and short-circuit when they collapse to <= 0.
- Validate numeric inputs at the form/API boundary before reaching the SDK.
- Treat 0 / negative as a no-op rather than forwarding to the SDK.
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.