amark/gun · error · TypeError

Invalid first argument for type 'hex'.

Error message

Invalid first argument for type 'hex'.

What it means

SafeBuffer.from with encoding 'hex' decodes the input string by matching pairs of hex digits. It throws a TypeError when the string contains no valid hex character pairs, i.e. nothing matched the /([\da-fA-F]{2})/g pattern, so no bytes could be produced.

Source

Thrown at sea/buffer.js:29

      console.warn('new SafeBuffer() is depreciated, please use SafeBuffer.from()')
      return SafeBuffer.from(...props)
    }
    SafeBuffer.prototype = Object.create(Array.prototype)
    Object.assign(SafeBuffer, {
      // (data, enc) where typeof data === 'string' then enc === 'utf8'|'hex'|'base64'
      from() {
        if (!Object.keys(arguments).length || arguments[0]==null) {
          throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
        }
        const input = arguments[0]
        let buf
        if (typeof input === 'string') {
          const enc = arguments[1] || 'utf8'
          if (enc === 'hex') {
            const bytes = input.match(/([\da-fA-F]{2})/g)
            .map((byte) => parseInt(byte, 16))
            if (!bytes || !bytes.length) {
              throw new TypeError('Invalid first argument for type \'hex\'.')
            }
            buf = SeaArray.from(bytes)
          } else if (enc === 'utf8' || 'binary' === enc) { // EDIT BY MARK: I think this is safe, tested it against a couple "binary" strings. This lets SafeBuffer match NodeJS Buffer behavior more where it safely btoas regular strings.
            const length = input.length
            const words = new Uint16Array(length)
            Array.from({ length: length }, (_, i) => words[i] = input.charCodeAt(i))
            buf = SeaArray.from(words)
          } else if (enc === 'base64') {
            const dec = atob(input)
            const length = dec.length
            const bytes = new Uint8Array(length)
            Array.from({ length: length }, (_, i) => bytes[i] = dec.charCodeAt(i))
            buf = SeaArray.from(bytes)
          } else if (enc === 'binary') { // deprecated by above comment
            buf = SeaArray.from(input) // some btoas were mishandled.
          } else {
            console.info('SafeBuffer.from unknown encoding: '+enc)
          }

View on GitHub (pinned to 552227599d)

Solutions

  1. Validate the string is non-empty hex before calling: /^[0-9a-fA-F]+$/ and even length
  2. Confirm the correct encoding — the data may actually be base64 or utf8, not hex
  3. Check the config/env/source actually contains the expected hex payload
  4. Trim whitespace and any '0x' prefix, which are not matched as valid hex pairs

Example fix

// before
const bytes = SafeBuffer.from(raw, 'hex'); // throws when raw isn't hex
// after
if (!/^[0-9a-fA-F]+$/.test(raw || '') || raw.length % 2 !== 0) {
  throw new Error('expected even-length hex string');
}
const bytes = SafeBuffer.from(raw, 'hex');
Defensive patterns

Strategy: validation

Validate before calling

function isHex(s) {
  return typeof s === 'string' && s.length > 0 && s.length % 2 === 0 && /^[0-9a-fA-F]+$/.test(s);
}
if (!isHex(raw)) throw new Error('expected even-length hex string');

Type guard

const isHexString = (v) => typeof v === 'string' && /^[0-9a-fA-F]*$/.test(v);

Try / catch

try {
  const bytes = SafeBuffer.from(raw, 'hex');
} catch (e) {
  console.error('not valid hex:', raw);
  throw e;
}

Prevention

When it happens

Trigger: Calling SafeBuffer.from(str, 'hex') where str is empty (''), contains no hex-pair characters (e.g. 'zzzz', 'xyz'), or is plain prose — note match() returns null for no matches, and the check `!bytes || !bytes.length` catches both. Strings with odd-length hex or partial junk will NOT throw (match silently skips invalid chars), so this fires mainly for fully non-hex input.

Common situations: Loading a hex-encoded key/secret from env or config that was never set or is placeholder text; decoding user input that was expected to be hex but was pasted as base64 or raw text; schema changes where a field switched from hex to utf8 encoding.

Related errors


AI-assisted analysis of amark/gun@552227599d (2026-09-02). Data as JSON: /api/errors/541de83fe43c461c. Report an issue: GitHub.