websockets/ws · critical · TypeError

One and only one of the "port", "server", or "noServer"…

Error message

One and only one of the "port", "server", or "noServer" options must be specified

What it means

Thrown by the WebSocketServer constructor at websocket-server.js:91-100. The server needs exactly one way to receive upgrade requests: either it creates its own HTTP server (port), reuses an existing one (server), or defers upgrade handling entirely to the user (noServer). The XOR logic rejects zero options (nothing to listen on) and any combination of two or three (ambiguous ownership of the upgrade event).

Solutions

  1. Pick exactly one: new WebSocketServer({ port: 8080 }) to create an internal server, new WebSocketServer({ server }) to attach to an existing HTTP server, or new WebSocketServer({ noServer: true }) to handle upgrades manually.
  2. If migrating modes, delete the now-unused option keys rather than setting them to null/undefined (port == null covers both null and undefined via ==).
  3. Double-check that no option is accidentally inherited from a spread/merge of another config object.

Example fix

// before
const wss = new WebSocketServer({ port: 8080, server: httpServer });

// after — use ONE mode only
const wss = new WebSocketServer({ server: httpServer });
Defensive patterns

Strategy: validation

Validate before calling

function validateServerOptions(options) {
  const modes = ['port', 'server', 'noServer']
    .filter(k => options[k] != null && options[k] !== false);
  if (modes.length !== 1) {
    throw new TypeError(
      'Pass exactly one of: { port }, { server }, or { noServer: true }'
    );
  }
}

Type guard

function isSingleServerMode(options) {
  const count =
    (options.port != null ? 1 : 0) +
    (options.server ? 1 : 0) +
    (options.noServer ? 1 : 0);
  return count === 1;
}

Try / catch

try {
  wss = new WebSocketServer(config);
} catch (err) {
  if (/port.*server.*noServer/.test(err.message)) {
    // fix config to use exactly one mode, then retry
    config = { noServer: true };
    wss = new WebSocketServer(config);
  } else throw err;
}

Prevention

When it happens

Trigger: Constructing new WebSocketServer({}) with none of the three options; passing both { port: 8080, server: httpServer }; passing { server: httpServer, noServer: true }; passing { port: 8080, noServer: true }; or all three at once. The three-way XOR at lines 92-94 fires for any combination other than exactly one.

Common situations: Forgetting to pass any option (empty constructor); copy-pasting from an example that used `server` while also keeping a `port` from another example; migrating from port mode to noServer mode but forgetting to remove the old option; TypeScript users whose optional fields all evaluate to undefined.

Related errors


AI-assisted analysis of websockets/ws@c791e707ea (2026-08-06). Data as JSON: /api/errors/c344e592076342c2. Report an issue: GitHub.

Appendix: source

Thrown at lib/websocket-server.js:96

      clientTracking: true,
      closeTimeout: CLOSE_TIMEOUT,
      verifyClient: null,
      noServer: false,
      backlog: null, // use default (511 as implemented in net.js)
      server: null,
      host: null,
      path: null,
      port: null,
      WebSocket,
      ...options
    };

    if (
      (options.port == null && !options.server && !options.noServer) ||
      (options.port != null && (options.server || options.noServer)) ||
      (options.server && options.noServer)
    ) {
      throw new TypeError(
        'One and only one of the "port", "server", or "noServer" options ' +
          'must be specified'
      );
    }

    if (options.port != null) {
      this._server = http.createServer((req, res) => {
        const body = http.STATUS_CODES[426];

        res.writeHead(426, {
          'Content-Length': body.length,
          'Content-Type': 'text/plain'
        });
        res.end(body);
      });
      this._server.listen(
        options.port,
        options.host,

View on GitHub (pinned to c791e707ea)