FuelLabs/fuels-ts · error · FuelError
DECODE_ERROR
DECODE_ERROR
Error message
Invalid vec data size.
What it means
Thrown by VecCoder.decode() under two conditions: (1) the vector has no nested Option fields and the data buffer is shorter than WORD_SIZE (8 bytes), too small to read the u64 element-count prefix; or (2) the data buffer exceeds MAX_BYTES (2^32 - 1), a safety guard against unreasonably large or potentially malicious payloads. Both indicate the data cannot be safely decoded.
Source
Thrown at packages/abi-coder/src/encoding/coders/VecCoder.ts:50
`Expected array value, or a Uint8Array. You can use arrayify to convert a value to a Uint8Array.`
);
}
const lengthCoder = new BigNumberCoder('u64');
if (isUint8Array(value)) {
return new Uint8Array([...lengthCoder.encode(value.length), ...value]);
}
const bytes = value.map((v) => this.coder.encode(v));
const lengthBytes = lengthCoder.encode(value.length);
return new Uint8Array([...lengthBytes, ...concatBytes(bytes)]);
}
decode(data: Uint8Array, offset: number): [DecodedValueOf<TCoder>, number] {
if ((!this.#hasNestedOption && data.length < this.encodedLength) || data.length > MAX_BYTES) {
throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid vec data size.`);
}
const offsetAndLength = offset + WORD_SIZE;
const lengthBytes = data.slice(offset, offsetAndLength);
const length = bn(new BigNumberCoder('u64').decode(lengthBytes, 0)[0]).toNumber();
const dataLength = length * this.coder.encodedLength;
const dataBytes = data.slice(offsetAndLength, offsetAndLength + dataLength);
if (!this.#hasNestedOption && dataBytes.length !== dataLength) {
throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid vec byte data size.`);
}
let newOffset = offsetAndLength;
const chunks = [];
for (let i = 0; i < length; i++) {
const [decoded, optionOffset] = this.coder.decode(data, newOffset);
chunks.push(decoded);
newOffset = optionOffset;View on GitHub (pinned to b3f37c91ac)
Solutions
- Verify data.length is between 8 and MAX_BYTES before calling decode().
- Validate data size from untrusted sources before attempting to decode.
- Check for truncation or corruption in the data pipeline.
Example fix
// before
vecCoder.decode(new Uint8Array([0, 1, 2]), 0); // throws DECODE_ERROR
// after
const MAX_BYTES = 2 ** 32 - 1;
if (data.length < 8 || data.length > MAX_BYTES) {
throw new Error('Invalid vec data size');
}
vecCoder.decode(data, 0); Defensive patterns
Strategy: validation
Validate before calling
const MAX_BYTES = 2 ** 32 - 1;
function canDecodeVec(data: Uint8Array): boolean {
return data.length >= 8 && data.length <= MAX_BYTES;
} Try / catch
try {
const [decoded, offset] = vecCoder.decode(data, 0);
} catch (e) {
if (e instanceof FuelError && e.code === ErrorCode.DECODE_ERROR) {
// data too short or exceeds MAX_BYTES; reject the payload
}
throw e;
} Prevention
- Size-check all incoming ABI payloads before decoding.
- Treat MAX_BYTES violations as potential DoS attempts from untrusted sources.
- Validate the u64 length prefix against reasonable application-level limits.
When it happens
Trigger: Passing fewer than 8 bytes to decode(), failing the minimum-size check. Receiving a corrupted or adversarial payload whose total size exceeds MAX_BYTES (approximately 4 GB). Both conditions indicate data that is either truncated or dangerously oversized.
Common situations: Truncated RPC data failing the minimum-size check. Corrupted or adversarial data triggering the MAX_BYTES guard. Memory exhaustion scenarios with very large vectors from untrusted sources.
Related errors
AI-assisted analysis of FuelLabs/fuels-ts@b3f37c91ac (2026-08-12).
Data as JSON: /api/errors/feeca4d5b934ecd6.
Report an issue: GitHub.