denoland/deno · error · NodeError
ERR_IPC_DISCONNECTED
ERR_IPC_DISCONNECTED
Error message
IPC channel is already disconnected
What it means
disconnect() throws ERR_IPC_DISCONNECTED when target.connected is already false — meaning disconnect() was called twice, or the other side (or child exit) already closed the channel. The flag flips synchronously on the first call, so the second call is the one that throws. Node uses the same code and message.
Source
Thrown at ext/node/polyfills/internal/child_process.ts:2944
let handleInfo = null;
if (handle !== undefined) {
handleInfo = getIpcHandleInfo(handle, options, target);
// `getIpcHandleInfo` returns null when the handle has no underlying
// native handle (e.g. a server that never started listening). Match
// Node, which strips the handle and sends the plain message instead.
if (handleInfo !== null) {
handleInfo.message.msg = message;
}
}
return enqueueOrDispatch(message, handleInfo, callback);
};
target.connected = true;
target.disconnect = function () {
if (!target.connected) {
throw new ERR_IPC_DISCONNECTED();
}
target.connected = false;
target[kCanDisconnect] = false;
cleanupPendingHandles();
control[kControlDisconnect]();
nextTick(() => {
target.channel = null;
core.close(ipc);
target.emit("disconnect");
});
};
target[kCanDisconnect] = true;
// Start reading messages from the channel.
readLoop();
return control;View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Guard the call: if (child.connected) child.disconnect() — or process.connected in a worker
- Make teardown idempotent with a single shutdown flag and one registration point
- Treat the 'disconnect' event as the authoritative signal instead of re-calling disconnect
Example fix
// before
function shutdown() {
child.disconnect();
}
process.on("SIGTERM", shutdown);
child.on("exit", shutdown); // second call throws
// after
let disconnected = false;
function shutdown() {
if (disconnected || !child.connected) return;
disconnected = true;
child.disconnect();
} Defensive patterns
Strategy: validation
Validate before calling
if (child.connected) {
child.disconnect();
}
// in a worker: if (process.connected) process.disconnect(); Try / catch
try {
child.disconnect();
} catch (err) {
if (err.code !== "ERR_IPC_DISCONNECTED") throw err;
// channel already gone; treat as success during shutdown
} Prevention
- Always guard disconnect() with the connected flag
- Register teardown exactly once; use an idempotent shutdown wrapper
- Listen for the 'disconnect' event instead of re-calling disconnect defensively
When it happens
Trigger: Calling child.disconnect() twice; calling process.disconnect() in a worker after the primary already disconnected; disconnect() reached from both a signal handler and an exit handler.
Common situations: Shutdown code that runs more than once (SIGTERM plus beforeExit); races between parent teardown and worker disconnect logic; code that ignores the 'disconnect' event and re-calls disconnect defensively.
Related errors
- ERR_INVALID_HANDLE_TYPE
- ipc stream closed while reading message
- ipc stream closed before message length
- ERR_CHILD_PROCESS_IPC_REQUIRED
- ERR_IPC_ONE_PIPE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/fb6df708d0a85066.
Report an issue: GitHub.