sveltejs/kit · error · Error

only one socket is allowed for socket activation, but LISTEN

Error message

only one socket is allowed for socket activation, but LISTEN_FDS was set to ${listen_fds}

What it means

The sd_listen_fds socket-activation protocol can pass multiple inherited file descriptors, but adapter-node is designed to take over exactly one listening socket. If LISTEN_FDS reports more than one, the adapter cannot know which to use and throws instead of guessing.

Source

Thrown at packages/adapter-node/src/index.js:24

import { rm } from 'node:fs/promises';
import { format_listening_address } from './utils.js';

export const path = env('SOCKET_PATH', false);
export const host = env('HOST', '0.0.0.0');
export const port = env('PORT', !path && '3000');

const shutdown_timeout = parseInt(env('SHUTDOWN_TIMEOUT', '30'));
const idle_timeout = parseInt(env('IDLE_TIMEOUT', '0'));
const listen_pid = parseInt(env('LISTEN_PID', '0'));
const listen_fds = parseInt(env('LISTEN_FDS', '0'));
// https://www.freedesktop.org/software/systemd/man/latest/sd_listen_fds.html
const SD_LISTEN_FDS_START = 3;

if (listen_pid !== 0 && listen_pid !== process.pid) {
	throw new Error(`received LISTEN_PID ${listen_pid} but current process id is ${process.pid}`);
}
if (listen_fds > 1) {
	throw new Error(
		`only one socket is allowed for socket activation, but LISTEN_FDS was set to ${listen_fds}`
	);
}

const socket_activation = listen_pid === process.pid && listen_fds === 1;

let requests = 0;
/** @type {NodeJS.Timeout | void} */
let shutdown_timeout_id;
/** @type {NodeJS.Timeout | void} */
let idle_timeout_id;

const httpServer = http.createServer();

const keep_alive_timeout = timeout_env('KEEP_ALIVE_TIMEOUT');
if (keep_alive_timeout !== undefined) {
	// Convert the keep-alive timeout from seconds to milliseconds (the unit Node.js expects).
	httpServer.keepAliveTimeout = keep_alive_timeout * 1000;

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Reduce the systemd socket unit to a single ListenStream= (split extra ports into separate services)
  2. Unset LISTEN_FDS if you do not intend to use socket activation: `env -u LISTEN_FDS node build`
  3. Handle additional ports inside the SvelteKit app or a reverse proxy instead of via multiple activated sockets
  4. Check `systemctl show <socket> -p Listen` to count how many fds the unit passes

Example fix

# before (myapp.socket)
[Socket]
ListenStream=3000
ListenStream=3001
# after
[Socket]
ListenStream=3000
Defensive patterns

Strategy: validation

Validate before calling

const fds = parseInt(process.env.LISTEN_FDS ?? '0', 10);
if (fds > 1) throw new Error(`socket activation expects 1 fd, got ${fds}; fix your .socket unit`);

Type guard

const hasSingleActivatedSocket = (env = process.env) => {
  const n = parseInt(env.LISTEN_FDS ?? '0', 10);
  return Number.isFinite(n) && n <= 1;
};

Try / catch

try {
  startServer();
} catch (err) {
  if (/LISTEN_FDS/.test(err.message)) {
    console.error('Multiple activated sockets not supported — use a single ListenStream.');
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: LISTEN_FDS is set to a value greater than 1 in the environment when the adapter-node server starts.

Common situations: systemd socket unit defines multiple ListenStream/Liste­nDatagram entries; several sockets are passed to the service; a leftover LISTEN_FDS env var leaks into a non-socket-activated deployment.

Related errors


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/346d8c9ccb2a3ea9. Report an issue: GitHub.