FuelLabs/fuels-ts · error · FuelError
ABI_TYPES_AND_VALUES_MISMATCH
ABI_TYPES_AND_VALUES_MISMATCH
Error message
Invalid number of arguments. Expected a minimum of ${mandatoryInputLength} arguments, received ${values.length} What it means
Thrown by `FunctionFragment.encodeArguments` (FuelError code `ABI_TYPES_AND_VALUES_MISMATCH`) when the number of values passed is less than the count of non-optional inputs declared in the ABI. Only `Option<T>` inputs are treated as optional and may be omitted; every other input is mandatory.
Source
Thrown at packages/abi-coder/src/FunctionFragment.ts:62
private static getSignature(abi: JsonAbiOld, fn: JsonAbiFunction): string {
const inputsSignatures = fn.inputs.map((input) =>
new ResolvedAbiType(abi, input).getSignature()
);
return `${fn.name}(${inputsSignatures.join(',')})`;
}
private static getFunctionSelector(functionSignature: string) {
const hashedFunctionSignature = sha256(bufferFromString(functionSignature, 'utf-8'));
// get first 4 bytes of signature + 0x prefix. then left-pad it to 8 bytes using toHex(8)
return bn(hashedFunctionSignature.slice(0, 10)).toHex(8);
}
encodeArguments(values: InputValue[]): Uint8Array {
const inputs = getFunctionInputs({ jsonAbi: this.jsonAbiOld, inputs: this.jsonFnOld.inputs });
const mandatoryInputLength = inputs.filter((i) => !i.isOptional).length;
if (values.length < mandatoryInputLength) {
throw new FuelError(
ErrorCode.ABI_TYPES_AND_VALUES_MISMATCH,
`Invalid number of arguments. Expected a minimum of ${mandatoryInputLength} arguments, received ${values.length}`
);
}
const coders = this.jsonFnOld.inputs.map((t) =>
AbiCoder.getCoder(this.jsonAbiOld, t, {
encoding: this.encoding,
})
);
const argumentValues = padValuesWithUndefined(values, this.jsonFn.inputs);
return new TupleCoder(coders).encode(argumentValues);
}
decodeArguments(data: BytesLike) {
const bytes = arrayify(data);
const nonVoidInputs = findNonVoidInputs(this.jsonAbiOld, this.jsonFnOld.inputs);View on GitHub (pinned to b3f37c91ac)
Solutions
- Pass an argument for every non-optional input; the error message states the exact `mandatoryInputLength` expected vs. received.
- Re-run `fuels typegen` so generated TS types force the correct arity at compile time.
- If an input was newly made optional in Sway, recompile the contract and regenerate bindings so it is treated as optional.
- For dynamic call sites, filter `functionFragment.jsonFnOld.inputs` and ensure your values array covers every non-optional input.
Example fix
// before — ABI: function foo(u64, u64) await contract.functions.foo(1).call(); // after await contract.functions.foo(1, 2).call();
Defensive patterns
Strategy: validation
Validate before calling
// before calling, ensure you cover every non-optional input
const mandatory = functionFragment.jsonFnOld.inputs.filter(
(i) => !getFunctionInputs({ jsonAbi: functionFragment.jsonAbiOld, inputs: [i] })[0].isOptional
);
if (values.length < mandatory.length) {
throw new Error(`Missing ${mandatory.length - values.length} required argument(s)`);
} Try / catch
try {
await contract.functions.foo(...args).call();
} catch (e) {
if (e.code === 'ABI_TYPES_AND_VALUES_MISMATCH') {
console.error('Argument mismatch for foo. Expected:', e.message);
}
throw e;
} Prevention
- Always regenerate types after ABI changes so TS enforces arity at compile time.
- Never bypass generated function types with `as any`.
- For dynamic call sites, build argument arrays from the ABI's input list.
When it happens
Trigger: Calling `contract.functions.foo(a)` when `foo` declares two non-optional inputs; omitting a required argument because TypeScript types were bypassed (`as any`); calling `.encodeArguments([...])` directly with a short array.
Common situations: ABI regenerated with new required inputs but call sites not updated; bypassing generated types; dynamically building argument arrays from a partial data source.
Related errors
AI-assisted analysis of FuelLabs/fuels-ts@b3f37c91ac (2026-08-12).
Data as JSON: /api/errors/a11a1a8e2b717fe3.
Report an issue: GitHub.