FuelLabs/fuels-ts · error · FuelError

ENCODE_ERROR

ENCODE_ERROR

Error message

Invalid ${this.type}.

What it means

Thrown by B512Coder.encode (this.type resolves to 'struct B512', so the message reads "Invalid struct B512.") when arrayify() rejects the input. arrayify only accepts a Uint8Array or a string matching /^0x([0-9a-f][0-9a-f])*$/i; anything else is caught and re-thrown as ENCODE_ERROR before any length check runs. A B512 is a 64-byte FuelVM signature value, so the input must be parseable bytes first.

Source

Thrown at packages/abi-coder/src/encoding/coders/B512Coder.ts:19

import { ErrorCode, FuelError } from '@fuel-ts/errors';
import { bn, toHex } from '@fuel-ts/math';
import { arrayify } from '@fuel-ts/utils';

import { WORD_SIZE } from '../../utils/constants';

import { Coder } from './AbstractCoder';

export class B512Coder extends Coder<string, string> {
  constructor() {
    super('b512', 'struct B512', WORD_SIZE * 8);
  }

  encode(value: string): Uint8Array {
    let encodedValue;
    try {
      encodedValue = arrayify(value);
    } catch (error) {
      throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`);
    }
    if (encodedValue.length !== this.encodedLength) {
      throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`);
    }
    return encodedValue;
  }

  decode(data: Uint8Array, offset: number): [string, number] {
    if (data.length < this.encodedLength) {
      throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid b512 data size.`);
    }

    let bytes = data.slice(offset, offset + this.encodedLength);

    const decoded = bn(bytes);
    if (decoded.isZero()) {
      bytes = new Uint8Array(64);
    }

View on GitHub (pinned to b3f37c91ac)

Solutions

  1. Normalize the value to a '0x'-prefixed hex string before encode, prepending '0x' if missing.
  2. If you hold raw bytes, pass a Uint8Array (arrayify accepts it) or convert with hexlify first.
  3. Validate the format with a regex and confirm it is exactly 128 hex chars before calling encode.
  4. Trace where the signature originated to stop the malformed value at the source instead of patching at encode time.

Example fix

// before
sigCoder.encode(sigStr) // sigStr lost its '0x' prefix in transit

// after
const clean = sigStr.startsWith('0x') ? sigStr : `0x${sigStr}`
sigCoder.encode(clean)
Defensive patterns

Strategy: validation

Validate before calling

const B512_HEX = /^0x[0-9a-fA-F]{128}$/
function isValidB512(v: unknown): v is string {
  return typeof v === 'string' && B512_HEX.test(v)
}
if (!isValidB512(value)) throw new Error('expected 0x-prefixed 64-byte hex')
sigCoder.encode(value)

Type guard

const isHexString = (v: unknown): v is string =>
  typeof v === 'string' && /^0x([0-9a-fA-F]{2})*$/.test(v)

Try / catch

try { sigCoder.encode(value) }
catch (e) { if ((e as FuelError).code === ErrorCode.ENCODE_ERROR) { /* normalize value or surface input error */ } throw e }

Prevention

When it happens

Trigger: Calling b512.encode(value), or encoding any function input typed as b512 via Interface/Contract, where value is a string that fails the hex regex: missing '0x' prefix, an odd number of hex digits, non-hex characters (e.g. spaces, '0X' capitalized 'X' path is fine but raw base64/filename text is not), or a non-string/non-Uint8Array runtime value.

Common situations: A signature that lost its '0x' during JSON round-trip; passing a base64 or PEM string instead of hex; a value that was coerced to a number and back to a decimal string; copy/paste truncating the hex; feeding a wallet recovery phrase or address where a signature was expected.

Related errors


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