zloirock/core-js · error · SyntaxError

String should be an even number of characters

Error message

String should be an even number of characters

What it means

Uint8Array.fromHex() requires the input to be a hex string with an even number of characters, since every byte is exactly two hex digits. If string.length % 2 !== 0 (a nibble is missing), decoding is ambiguous and the library throws this SyntaxError before any bytes are written.

Source

Thrown at packages/core-js/internals/uint8-from-hex.js:12

'use strict';
var globalThis = require('../internals/global-this');
var uncurryThis = require('../internals/function-uncurry-this');

var Uint8Array = globalThis.Uint8Array;
var SyntaxError = globalThis.SyntaxError;
var min = Math.min;
var stringMatch = uncurryThis(''.match);

module.exports = function (string, into) {
  var stringLength = string.length;
  if (stringLength % 2 !== 0) throw new SyntaxError('String should be an even number of characters');
  var maxLength = into ? min(into.length, stringLength / 2) : stringLength / 2;
  var bytes = into || new Uint8Array(maxLength);
  var segments = stringMatch(string, /[\S\s]{2}/g);
  var written = 0;
  for (; written < maxLength; written++) {
    var result = +('0x' + segments[written] + '0');
    // eslint-disable-next-line no-self-compare -- NaN check
    if (result !== result) {
      throw new SyntaxError('String should only contain hex characters');
    }
    bytes[written] = result >> 4;
  }
  return { bytes: bytes, read: written << 1 };
};

View on GitHub (pinned to 84e45fba09)

Solutions

  1. Pad the string to even length with a leading '0' if a single leading nibble was dropped: s.length % 2 ? '0' + s : s.
  2. Fix the producer to zero-pad each byte to two hex digits (e.g. n.toString(16).padStart(2, '0')).
  3. Verify the string wasn't truncated in storage/transport; compare length to the expected byteCount * 2.
  4. Catch SyntaxError at the boundary and report 'odd-length hex string' to the caller.

Example fix

// before
Uint8Array.fromHex('4a617'); // SyntaxError: String should be an even number of characters
// after
const hex = raw.length % 2 === 0 ? raw : '0' + raw;
const bytes = Uint8Array.fromHex(hex);
Defensive patterns

Strategy: validation

Validate before calling

function isEvenLengthHex(s) {
  return typeof s === 'string' && /^[0-9a-fA-F]*$/.test(s) && s.length % 2 === 0;
}
// if (!isEvenLengthHex(input)) input = input.padStart(input.length + (input.length % 2), '0');

Type guard

function isHexString(s) {
  return typeof s === 'string' && s.length % 2 === 0 && /^[0-9a-fA-F]+$/.test(s);
}

Try / catch

try {
  const bytes = Uint8Array.fromHex(input);
} catch (e) {
  if (e instanceof SyntaxError && e.message.includes('even number of characters')) {
    throw new TypeError(`Hex string must have even length, got ${input.length}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling Uint8Array.fromHex('abc') or fromHexInto with any odd-length string — e.g. a hex string missing its last character, produced by a '%x' format that dropped a leading zero ('0x5' instead of '05' concatenated), or manually built nibble-by-nibble.

Common situations: Formatting individual bytes with '0x%x' without zero-padding so '0x0A' becomes 'a', string truncation by fixed-length buffers, copy/paste dropping a character, or concatenating hex nibbles instead of byte pairs.

Related errors


AI-assisted analysis of zloirock/core-js@84e45fba09 (2026-08-30). Data as JSON: /api/errors/e75a6b1f09d98d4d. Report an issue: GitHub.