FuelLabs/fuels-ts · error · FuelError
COINS_ASSET_ID_MISMATCH
COINS_ASSET_ID_MISMATCH
Error message
All coins to consolidate must be from the same asset id.
What it means
Thrown by validateConsolidationTxsCoins when the coins array contains UTXOs whose assetId does not match the assetId being consolidated. Consolidation builds one transaction against a single asset, so any foreign-asset coin would corrupt the output accounting. This guard runs in both the base-asset and non-base-asset assembly paths.
Source
Thrown at packages/account/src/account.ts:1279
/** @hidden * */
private validateTransferAmount(amount: BigNumberish) {
if (bn(amount).lte(0)) {
throw new FuelError(
ErrorCode.INVALID_TRANSFER_AMOUNT,
'Transfer amount must be a positive number.'
);
}
}
/** @hidden * */
private validateConsolidationTxsCoins(coins: Coin[], assetId: string) {
if (coins.length <= 1) {
throw new FuelError(ErrorCode.NO_COINS_TO_CONSOLIDATE, 'No coins to consolidate.');
}
if (!coins.every((c) => c.assetId === assetId)) {
throw new FuelError(
ErrorCode.COINS_ASSET_ID_MISMATCH,
'All coins to consolidate must be from the same asset id.'
);
}
}
/** @hidden * */
private async setTransactionStateForConnectors(params: {
transactionRequest: TransactionRequest;
connectorOptions: AccountSendTxParams;
}): Promise<{
transactionRequest: TransactionRequest;
connectorsSendTxParams: FuelConnectorSendTxParams;
}> {
const { transactionRequest: requestToPrepare, connectorOptions } = params;
const { onBeforeSend, skipCustomFee = false } = connectorOptions;
View on GitHub (pinned to b3f37c91ac)
Solutions
- Always fetch coins with the asset filter: provider.getCoins(account.address, assetId).
- If using a cached list, filter it right before the call: coins.filter(c => c.assetId === assetId).
- Group coins by assetId first and consolidate each group separately.
Example fix
// before
const { coins } = await provider.getCoins(account.address);
await account.consolidateCoins({ assetId });
// after
const { coins } = await provider.getCoins(account.address, assetId);
await account.consolidateCoins({ assetId }); Defensive patterns
Strategy: validation
Validate before calling
// Always fetch coins with the asset filter so the array is homogeneous
const { coins } = await provider.getCoins(account.address, assetId);
await account.consolidateCoins({ assetId });
// or sanitize an existing list:
const homogeneous = coins.filter(c => c.assetId === assetId); Type guard
function allSameAsset(coins: Coin[], assetId: string): boolean {
return coins.every(c => c.assetId === assetId);
} Try / catch
try {
await account.consolidateCoins({ assetId });
} catch (e) {
if (e instanceof FuelError && e.code === ErrorCode.COINS_ASSET_ID_MISMATCH) {
// re-fetch with the correct asset filter and retry
} else throw e;
} Prevention
- Always pass the assetId filter to provider.getCoins when consolidating.
- Filter cached coin lists by assetId immediately before use.
- Group coins by assetId and consolidate each group separately.
When it happens
Trigger: Passing a coins array (or letting getCoins fetch one) that mixes assetIds, then calling account.consolidateCoins({ assetId }) or account.assembleNonBaseAssetConsolidationTxs({ assetId, coins }) where not every coin.assetId === assetId.
Common situations: Fetching all coins for an address (no asset filter) and feeding them to consolidateCoins for a specific asset; mutating assetId mid-loop; off-by-one when slicing a cached coin list.
Related errors
AI-assisted analysis of FuelLabs/fuels-ts@b3f37c91ac (2026-08-12).
Data as JSON: /api/errors/1b139aad4847e030.
Report an issue: GitHub.