denoland/deno · error

ipc stream closed while reading message

Error message

ipc stream closed while reading message

What it means

Deno's advanced (v8 serialization) IPC reader for node:child_process/node:cluster channels reads length-prefixed messages. If the pipe returns EOF (read == 0) after the message-length prefix was already parsed (length_buffer.message_len().is_some()) but before the full payload arrived, the partially received message is abandoned with ErrorKind::UnexpectedEof and this message.

Source

Thrown at ext/process/ipc.rs:394

          .read_buffer
          .fill_from_pipe(&mut self.pipe)
          .await
          .map_err(IpcAdvancedStreamError::Io)?;
      }

      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);

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Treat it as a child crash: listen for 'exit' and inspect code/signal; restart the child and replay any state it owned.
  2. Avoid process.exit() in the child while messages may be in flight; let the event loop drain or ack sends before exiting.
  3. Send large payloads in smaller chunks with application-level acks so a truncated stream loses less.
  4. Attach an 'error' handler on the child/worker so the UnexpectedEof is observed and handled, not fatal to the parent.

Example fix

// before
child.on('message', onMsg); // no error handling: truncated IPC message crashes the parent

// after
child.on('message', onMsg);
child.on('error', (err) => {
  if (err.code === 'UNEXPECTED_EOF' || /ipc stream closed while reading/.test(err.message)) {
    restartChild(); // peer died mid-message; treat as crash, not bug
  }
});
child.on('exit', (code, signal) => { if (signal) restartChild(); });
Defensive patterns

Strategy: try-catch

Try / catch

child.on("error", (e) => {
  if (/ipc stream closed while reading message/.test(e.message)) {
    // peer died mid-message: treat as crash, restart and replay state
    supervisor.restart(child);
  }
});

Prevention

When it happens

Trigger: The peer process dies or closes the channel mid-message: child killed by a signal while serializing a large object, abrupt process.exit() during send, OOM kill mid-write, or the channel being torn down before a big payload was flushed.

Common situations: fork() plus advanced serialization of large payloads; cluster workers crashing under load; children calling process.exit() while a send() is still buffered; memory-pressure kills truncating channel writes.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/e66f264e73bb808a. Report an issue: GitHub.