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.

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@a961cdec3b (2026-08-20). Data as JSON: /api/errors/27b6b67539c0a9b4. Report an issue: GitHub.

Appendix: source

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

  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 a961cdec3b)