denoland/deno · error · RangeError

Buffer size must be a multiple of 16-bits

Error message

Buffer size must be a multiple of 16-bits

What it means

Buffer.prototype.swap16() reverses bytes in place in 2-byte pairs (a 16-bit endianness flip, e.g. UTF-16LE <-> UTF-16BE). A buffer with an odd byte length cannot be divided into 2-byte pairs, so the method throws a plain RangeError before modifying any bytes. Same contract as Node's lib/internal/buffer.js.

Source

Thrown at ext/node/polyfills/internal/buffer.mjs:671

  const ops = getEncodingOps(encoding);
  if (ops === undefined) {
    return (mustMatch ? -1 : byteLengthUtf8(string));
  }
  return ops.byteLength(string);
}

Buffer.byteLength = byteLength;

function swap(b, n, m) {
  const i = b[n];
  b[n] = b[m];
  b[m] = i;
}

Buffer.prototype.swap16 = function swap16() {
  const len = this.length;
  if (len % 2 !== 0) {
    throw new RangeError("Buffer size must be a multiple of 16-bits");
  }
  for (let i = 0; i < len; i += 2) {
    swap(this, i, i + 1);
  }
  return this;
};

Buffer.prototype.swap32 = function swap32() {
  const len = this.length;
  if (len % 4 !== 0) {
    throw new RangeError("Buffer size must be a multiple of 32-bits");
  }
  for (let i = 0; i < len; i += 4) {
    swap(this, i, i + 3);
    swap(this, i + 1, i + 2);
  }
  return this;
};

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Check alignment first and handle the trailing byte explicitly (report truncation or pad)
  2. Trim to the largest even boundary when the last byte is padding: buf.subarray(0, buf.length - buf.length % 2).swap16()
  3. Validate the source length (file size, Content-Length, protocol length field) before endian conversion - odd length usually means truncated input
  4. Pad deliberately when the format expects it: Buffer.concat([buf, Buffer.alloc(1)]).swap16()

Example fix

// before
const buf = Buffer.from('abc'); // 3 bytes
buf.swap16(); // RangeError: Buffer size must be a multiple of 16-bits

// after
if (buf.length % 2 !== 0) throw new Error('truncated UTF-16 payload');
buf.swap16();
Defensive patterns

Strategy: validation

Validate before calling

function swap16Safe(buf) {
  if (buf.length % 2 !== 0) {
    throw new RangeError(`expected even byte length, got ${buf.length}`);
  }
  return buf.swap16();
}

Try / catch

try {
  buf.swap16();
} catch (e) {
  if (e instanceof RangeError) { /* record truncation, trim to even boundary, or refetch data */ }
  else throw e;
}

Prevention

When it happens

Trigger: buf.swap16() when buf.length % 2 !== 0, e.g. Buffer.from('abc').swap16() (3 bytes) or a 101-byte network frame parsed as UTF-16.

Common situations: Decoding UTF-16 files with a truncated final code unit (broken download, wrong length from a header); odd-length test fixtures; an off-by-one in slicing that leaves one stray byte before conversion.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/27b6b67539c0a9b4. Report an issue: GitHub.