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 UTF-8 byte length of the close-frame reason string exceeds 123 bytes. RFC 6455 caps all control frame (opcode 0x08) payloads at 125 bytes; the first 2 bytes carry the status code, leaving only 123 bytes for the human-readable reason. The library enforces this in sender.js:195-198 before attempting to build the frame, so an oversized reason never reaches the wire.
Solutions
- Truncate the reason to at most 123 bytes before calling close(): use reason = Buffer.from(reason).subarray(0, 123).toString() or slice the string so Buffer.byteLength(reason) <= 123.
- If you only need a status code, omit the reason entirely: ws.close(1000).
- Send lengthy diagnostic details via a preceding normal data message (ws.send) before closing, then close with a short or empty reason.
Example fix
// before ws.close(1000, longErrorStackMessage); // after const reason = Buffer.from(longErrorStackMessage).subarray(0, 123).toString(); ws.close(1000, reason);
Defensive patterns
Strategy: validation
Validate before calling
// Run before ws.close(code, reason) or sender.close()
function safeCloseReason(reason) {
if (reason == null) return undefined;
const buf = Buffer.from(reason);
return buf.length > 123 ? buf.subarray(0, 123).toString() : reason;
}
// usage: ws.close(1000, safeCloseReason(longMessage)); Type guard
function isValidCloseReason(data) {
return (
typeof data === 'string' ||
(data != null && typeof data === 'object' && ArrayBuffer.isView(data) && data.BYTES_PER_ELEMENT === 1)
); // string or Uint8Array/Buffer
} Try / catch
try {
ws.close(code, reason);
} catch (err) {
if (err instanceof RangeError && /123 bytes/.test(err.message)) {
ws.close(code, String(reason).slice(0, 123));
} else {
throw err;
}
} Prevention
- Always truncate close reasons to <= 123 bytes; use Buffer.byteLength to measure multi-byte strings.
- Omit the reason argument when you only need a status code.
- Send lengthy diagnostics via ws.send() before closing instead of stuffing them into the close frame.
When it happens
Trigger: Calling ws.close(code, reason) or the internal sender.close(code, data, mask, cb) where Buffer.byteLength(data) > 123. The check fires only when both a numeric code and a non-empty data argument are supplied (code !== undefined and data.length > 0), because the 123-byte limit applies to the reason body that follows the 2-byte status code.
Common situations: Passing a long diagnostic/stack-trace/error description as the close reason during graceful shutdown; internationalized reason strings whose multi-byte UTF-8 encoding exceeds 123 bytes even though the character count looks short; copying exception messages verbatim into ws.close() without truncation.
Related errors
- The data size must not be greater than 125 bytes
- Second argument must be a string or a Uint8Array
- Unexpected end of input
- An invalid or duplicated subprotocol was specified
- First argument must be a valid error code number
AI-assisted analysis of websockets/ws@c791e707ea (2026-08-06).
Data as JSON: /api/errors/bcc03068003ec1f3.
Report an issue: GitHub.
Appendix: 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 c791e707ea)