denoland/deno · error
ipc stream closed before message length
Error message
ipc stream closed before message length
What it means
Same advanced IPC reader as the sibling 'closed while reading message' error, but EOF arrived before even the message-length prefix was complete (length_buffer.message_len().is_none()). The channel closed between the start of a header and its end, so no payload could even be partially assembled; the read fails with UnexpectedEof.
Source
Thrown at ext/process/ipc.rs:399
if let Some(fd) = self.read_buffer.take_raw_fd() {
debug_assert!(raw_fd.is_none());
if raw_fd.is_none() {
raw_fd = Some(fd);
}
}
let available = self.read_buffer.available_mut();
if available.is_empty() {
if read == 0 {
return Ok(None);
} else if length_buffer.message_len().is_some() {
return Err(IpcAdvancedStreamError::Io(io::Error::new(
io::ErrorKind::UnexpectedEof,
"ipc stream closed while reading message",
)));
} else {
return Err(IpcAdvancedStreamError::Io(io::Error::new(
io::ErrorKind::UnexpectedEof,
"ipc stream closed before message length",
)));
}
}
let msg_len = length_buffer.message_len();
let (done, used) = if let Some(msg_len) = msg_len {
if out_buf.len() >= msg_len {
(true, 0)
} else {
let remaining = msg_len - out_buf.len();
out_buf.reserve(remaining);
let to_copy = available.len().min(remaining);
out_buf.extend_from_slice(&available[..to_copy]);
(out_buf.len() == msg_len, to_copy)
}
} else {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Handle the error as 'channel torn down': wait for the child 'exit' event to get the real cause (signal vs clean exit).
- Order shutdown deliberately: stop sending, await an ack, then close/kill the child, so headers are never cut mid-write.
- Use graceful termination (SIGTERM + grace period) instead of SIGKILL so the child can finish writes.
- Register 'error' handlers on the channel/worker to convert the EOF into a supervised restart.
Example fix
// before
setTimeout(() => child.kill('SIGKILL'), 100); // can cut a length prefix mid-write
// after
child.send({ cmd: 'shutdown' }, () => {}); // let the child ack and exit cleanly
await once(child, 'exit');
child.on('error', (e) => { if (/ipc stream closed/.test(e.message)) restartChild(); }); Defensive patterns
Strategy: try-catch
Try / catch
child.on("error", (e) => { if (/ipc stream closed before message length/.test(e.message)) supervisor.restart(child); }); Prevention
- Shut down in order: stop producers, await ack, then terminate children.
- Prefer SIGTERM + grace period over SIGKILL so length headers are never cut mid-write.
- Keep message sends atomic (one write per message) where possible.
When it happens
Trigger: The peer closes or dies while a length prefix (few header bytes) was partially written: child killed between two write() calls, channel closed by the parent during teardown, or a worker exiting between messages leaving a torn header in the pipe.
Common situations: Races during shutdown/teardown of forked children; killing children with SIGKILL mid-send; channels closed by timeout logic exactly as a new message starts; test harnesses that terminate children aggressively.
Related errors
- ipc stream closed while reading message
- ERR_IPC_ONE_PIPE
- ERR_IPC_SYNC_FORK
- ERR_INVALID_HANDLE_TYPE
- ERR_IPC_DISCONNECTED
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/2026e3de39a9446e.
Report an issue: GitHub.