websockets/ws · error · RangeError

The message must not be greater than 123 bytes

Error message

The message must not be greater than 123 bytes

What it means

Thrown by Sender.close() when the optional 'data' (reason) argument passed alongside a numeric status code exceeds 123 bytes. The WebSocket close frame is a control frame, which RFC 6455 limits to 125 bytes of payload; 2 bytes are reserved for the status code, leaving at most 123 bytes for the reason text. The library enforces this in lib/sender.js:197-199 by measuring Buffer.byteLength(data) before constructing the frame.

Source

Thrown at lib/sender.js:198

   * @param {Boolean} [mask=false] Specifies whether or not to mask the message
   * @param {Function} [cb] Callback
   * @public
   */
  close(code, data, mask, cb) {
    let buf;

    if (code === undefined) {
      buf = EMPTY_BUFFER;
    } else if (typeof code !== 'number' || !isValidStatusCode(code)) {
      throw new TypeError('First argument must be a valid error code number');
    } else if (data === undefined || !data.length) {
      buf = Buffer.allocUnsafe(2);
      buf.writeUInt16BE(code, 0);
    } else {
      const length = Buffer.byteLength(data);

      if (length > 123) {
        throw new RangeError('The message must not be greater than 123 bytes');
      }

      buf = Buffer.allocUnsafe(2 + length);
      buf.writeUInt16BE(code, 0);

      if (typeof data === 'string') {
        buf.write(data, 2);
      } else if (isUint8Array(data)) {
        buf.set(data, 2);
      } else {
        throw new TypeError('Second argument must be a string or a Uint8Array');
      }
    }

    const options = {
      [kByteLength]: buf.length,
      fin: true,
      generateMask: this._generateMask,

View on GitHub (pinned to ae1de54330)

Solutions

  1. Truncate or shorten the reason so Buffer.byteLength(reason) <= 123 (remember multi-byte UTF-8 chars count more than one byte).
  2. If you need to send more context, deliver it in a final application message before calling close().
  3. Pass only a status code with no data argument (ws.close(code)) if the reason is non-essential.

Example fix

// before
ws.close(1000, veryLongErrorStack); // > 123 bytes

// after
const reason = veryLongErrorStack.slice(0, 100); // leave headroom for UTF-8
ws.close(1000, reason);
Defensive patterns

Strategy: validation

Validate before calling

function safeClose(ws, code, reason) {
  if (reason !== undefined) {
    const bytes = Buffer.byteLength(reason, 'utf8');
    if (bytes > 123) {
      reason = reason.slice(0, Math.max(0, 123 - (bytes - reason.length)));
      // or, simpler: truncate to a conservative char count
      while (Buffer.byteLength(reason, 'utf8') > 123) reason = reason.slice(0, -1);
    }
  }
  ws.close(code, reason);
}

Type guard

function isValidCloseReason(data) {
  return (
    data === undefined ||
    typeof data === 'string' ||
    (data instanceof Uint8Array && Buffer.byteLength(data) <= 123)
  );
}

Try / catch

try {
  ws.close(code, reason);
} catch (err) {
  if (err instanceof RangeError && /must not be greater than 123 bytes/.test(err.message)) {
    ws.close(code); // retry without oversized reason
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling ws.close(code, data) or ws.terminate()'s sibling ws.close() with a status code and a reason string (or Uint8Array) whose byte length exceeds 123. Internally, Sender.close(code, data, mask, cb) computes const length = Buffer.byteLength(data); and throws RangeError when length > 123. This also propagates from WebSocket.close() (websocket.js:322) which forwards code and data to the sender.

Common situations: Developers pasting long human-readable error descriptions or stack traces as the close reason; embedding JSON diagnostics into the close payload; localized multi-byte UTF-8 messages (e.g. CJK text) that are short in characters but exceed 123 bytes.

Related errors


AI-assisted analysis of websockets/ws@ae1de54330 (2026-08-03). Data as JSON: /data/errors/bcc03068003ec1f3.json. Report an issue: GitHub.