{"record":{"id":"281da683490519b6","repo":"rust-lang/rust","slug":"closed","errorCode":null,"errorMessage":"closed","messagePattern":"closed","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol.rs","lineNumber":48,"sourceCode":"\npub type SubCallback<'a> = &'a dyn Fn(SubRequest) -> Result<SubResponse, ServerError>;\n\npub fn run_conversation(\n    writer: &mut dyn Write,\n    reader: &mut dyn BufRead,\n    buf: &mut Vec<u8>,\n    msg: BidirectionalMessage,\n    callback: SubCallback<'_>,\n) -> Result<BidirectionalMessage, ServerError> {\n    let encoded = postcard::encode(&msg).map_err(wrap_encode)?;\n    postcard::write(writer, &encoded).map_err(wrap_io(\"failed to write initial request\"))?;\n\n    loop {\n        let maybe_buf = postcard::read(reader, buf).map_err(wrap_io(\"failed to read message\"))?;\n        let Some(b) = maybe_buf else {\n            return Err(ServerError {\n                message: \"proc-macro server closed the stream\".into(),\n                io: Some(Arc::new(io::Error::new(io::ErrorKind::UnexpectedEof, \"closed\"))),\n            });\n        };\n\n        let msg: BidirectionalMessage = postcard::decode(b).map_err(wrap_decode)?;\n\n        match msg {\n            BidirectionalMessage::Response(response) => {\n                return Ok(BidirectionalMessage::Response(response));\n            }\n            BidirectionalMessage::SubRequest(sr) => {\n                // TODO: Avoid `AssertUnwindSafe` by making the callback `UnwindSafe` once `SourceDatabase`\n                // becomes unwind-safe (currently blocked by `parking_lot::RwLock` in the VFS).\n                let resp = match catch_unwind(AssertUnwindSafe(|| callback(sr))) {\n                    Ok(Ok(resp)) => BidirectionalMessage::SubResponse(resp),\n                    Ok(Err(err)) => BidirectionalMessage::SubResponse(SubResponse::Cancel {\n                        reason: err.to_string(),\n                    }),\n                    Err(_) => BidirectionalMessage::SubResponse(SubResponse::Cancel {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/rust-lang/rust/blob/7088e4b63a9516ebfbfe2ab2d999cf01a528ac14/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol.rs#L30-L66","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the proc-macro-srv stderr/logs for the crash cause (panic, OOM, version mismatch).","Ensure rust-analyzer and proc-macro-srv come from the same toolchain/commit.","Temporarily disable the offending proc-macro crate to confirm it is the trigger.","Increase available memory / raise ulimits if proc-macro-srv is being OOM-killed."],"exampleFix":"// no code fix; this is a runtime server crash. Diagnostic step:\n// 1. Run: rustup run nightly proc-macro-srv\n// 2. Watch stderr for the panic, then fix the offending proc-macro crate.","handlingStrategy":"try-catch","validationCode":"// Validate the server is alive before sending.\n// if proc_macro_server.try_wait()?.is_some() { return Err(\"server exited\"); }","typeGuard":null,"tryCatchPattern":"match run_conversation(writer, reader, buf, msg, cb) {\n    Ok(r) => Ok(r),\n    Err(ServerError { io: Some(ref i), .. })\n        if i.kind() == io::ErrorKind::UnexpectedEof => {\n        // server crashed; log stderr, disable proc macros, degrade\n        Err(\"proc-macro server crashed mid-conversation\".into())\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Keep rust-analyzer and proc-macro-srv on the same toolchain/commit.","Watch proc-macro-srv stderr for panics during macro expansion.","Provide a config switch to disable the crashing proc-macro crate."],"tags":["rust-analyzer","proc-macro","ipc","protocol","eof","crash"],"backgroundTag":null,"analyzedSha":"7088e4b63a9516ebfbfe2ab2d999cf01a528ac14","analyzedAt":"2026-08-10T14:17:03.603Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}