rust-lang/rust · error · io::Error

closed

Error message

closed

What it means

Returned by rust-analyzer's bidirectional proc-macro protocol (run_conversation) when the postcard reader yields no buffer from the proc-macro server's stdout - i.e. the stream hit EOF. It is wrapped in a ServerError whose message is 'proc-macro server closed the stream' and whose io field is ErrorKind::UnexpectedEof with text 'closed'. This signals the proc-macro server process terminated mid-conversation.

Source

Thrown at src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol.rs:48

pub type SubCallback<'a> = &'a dyn Fn(SubRequest) -> Result<SubResponse, ServerError>;

pub fn run_conversation(
    writer: &mut dyn Write,
    reader: &mut dyn BufRead,
    buf: &mut Vec<u8>,
    msg: BidirectionalMessage,
    callback: SubCallback<'_>,
) -> Result<BidirectionalMessage, ServerError> {
    let encoded = postcard::encode(&msg).map_err(wrap_encode)?;
    postcard::write(writer, &encoded).map_err(wrap_io("failed to write initial request"))?;

    loop {
        let maybe_buf = postcard::read(reader, buf).map_err(wrap_io("failed to read message"))?;
        let Some(b) = maybe_buf else {
            return Err(ServerError {
                message: "proc-macro server closed the stream".into(),
                io: Some(Arc::new(io::Error::new(io::ErrorKind::UnexpectedEof, "closed"))),
            });
        };

        let msg: BidirectionalMessage = postcard::decode(b).map_err(wrap_decode)?;

        match msg {
            BidirectionalMessage::Response(response) => {
                return Ok(BidirectionalMessage::Response(response));
            }
            BidirectionalMessage::SubRequest(sr) => {
                // TODO: Avoid `AssertUnwindSafe` by making the callback `UnwindSafe` once `SourceDatabase`
                // becomes unwind-safe (currently blocked by `parking_lot::RwLock` in the VFS).
                let resp = match catch_unwind(AssertUnwindSafe(|| callback(sr))) {
                    Ok(Ok(resp)) => BidirectionalMessage::SubResponse(resp),
                    Ok(Err(err)) => BidirectionalMessage::SubResponse(SubResponse::Cancel {
                        reason: err.to_string(),
                    }),
                    Err(_) => BidirectionalMessage::SubResponse(SubResponse::Cancel {

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Check the proc-macro-srv stderr/logs for the crash cause (panic, OOM, version mismatch).
  2. Ensure rust-analyzer and proc-macro-srv come from the same toolchain/commit.
  3. Temporarily disable the offending proc-macro crate to confirm it is the trigger.
  4. Increase available memory / raise ulimits if proc-macro-srv is being OOM-killed.

Example fix

// no code fix; this is a runtime server crash. Diagnostic step:
// 1. Run: rustup run nightly proc-macro-srv
// 2. Watch stderr for the panic, then fix the offending proc-macro crate.
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the server is alive before sending.
// if proc_macro_server.try_wait()?.is_some() { return Err("server exited"); }

Try / catch

match run_conversation(writer, reader, buf, msg, cb) {
    Ok(r) => Ok(r),
    Err(ServerError { io: Some(ref i), .. })
        if i.kind() == io::ErrorKind::UnexpectedEof => {
        // server crashed; log stderr, disable proc macros, degrade
        Err("proc-macro server crashed mid-conversation".into())
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: rust-analyzer sends a BidirectionalMessage to proc-macro-srv and the server process crashes, is killed, or exits before responding; postcard::read returns None because the reader reached EOF. Common during proc-macro expansion when a macro panics inside the server or the server hits a fatal error.

Common situations: proc-macro-srv built against an incompatible toolchain; a derive/attribute macro panicking; OOM killing proc-macro-srv; mismatched protocol versions between rust-analyzer and proc-macro-srv; antivirus killing the child.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/281da683490519b6. Report an issue: GitHub.