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
- Reduce the systemd socket unit to a single ListenStream= (split extra ports into separate services)
- Unset LISTEN_FDS if you do not intend to use socket activation: `env -u LISTEN_FDS node build`
- Handle additional ports inside the SvelteKit app or a reverse proxy instead of via multiple activated sockets
- 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
- Keep one ListenStream= per systemd .socket unit
- `systemctl show <socket> -p Listen` to verify fd count before deploy
- Unset LISTEN_FDS in non-socket-activated environments
- Route extra ports through a reverse proxy instead of extra sockets
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/ListenDatagram entries; several sockets are passed to the service; a leftover LISTEN_FDS env var leaks into a non-socket-activated deployment.
Related errors
- received LISTEN_PID ${listen_pid} but current process id is
- You should change envPrefix (${env_prefix}) to avoid conflic
- Invalid value for environment variable ${env_prefix + name}:
- You should change envPrefix (${env_prefix}) to avoid conflic
- Invalid value for environment variable ${name}: ${JSON.strin
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/346d8c9ccb2a3ea9.
Report an issue: GitHub.