{"record":{"id":"231f960e3bbb1e42","repo":"rust-lang/rust-analyzer","slug":"join-e","errorCode":null,"errorMessage":"{join_e}","messagePattern":"\\{join_e\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/rust-analyzer/src/session.rs","lineNumber":166,"sourceCode":"        let not = lsp_server::Notification::new(\n            ShowMessageNotification::METHOD.into(),\n            ShowMessageParams { kind: MessageType::Warning, message: notice },\n        );\n        connection.sender.send(lsp_server::Message::Notification(not)).unwrap();\n    }\n\n    if config.discover_workspace_config().is_none()\n        && !config.has_linked_projects()\n        && config.detached_files().is_empty()\n    {\n        config.rediscover_workspaces();\n    }\n\n    // If the io_threads have an error, there's usually an error on the main\n    // loop too because the channels are closed. Ensure we report both errors.\n    match (crate::main_loop(config, connection), io_threads.join()) {\n        (Err(loop_e), Err(join_e)) => anyhow::bail!(\"{loop_e}\\n{join_e}\"),\n        (Ok(_), Err(join_e)) => anyhow::bail!(\"{join_e}\"),\n        (Err(loop_e), Ok(_)) => anyhow::bail!(\"{loop_e}\"),\n        (Ok(_), Ok(_)) => {}\n    }\n\n    tracing::info!(\"server did shut down\");\n    Ok(())\n}\n\nfn patch_path_prefix(path: PathBuf) -> PathBuf {\n    use std::path::{Component, Prefix};\n    if cfg!(windows) {\n        // VSCode might report paths with the file drive in lowercase, but this can mess\n        // with env vars set by tools and build scripts executed by r-a such that it invalidates\n        // cargo's compilations unnecessarily. https://github.com/rust-lang/rust-analyzer/issues/14683\n        // So we just uppercase the drive letter here unconditionally.\n        // (doing it conditionally is a pain because std::path::Prefix always reports uppercase letters on windows)\n        let mut comps = path.components();\n        match comps.next() {","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/rust-analyzer/src/session.rs#L148-L184","documentation":"Same `run_session` error handling, but for the case where the main loop finished normally while `io_threads.join()` still returned an error. The IO threads failed (read/write over the transport errored) even though the loop itself saw no fatal event.","triggerScenarios":"Calling `run_session` where `main_loop` returns `Ok` but `io_threads.join()` returns `Err`, typically when a write to the client fails (client stopped reading / closed stdout) during or at the end of a session.","commonSituations":"Client closes its stdout-read side early; EPIPE/ECONNRESET writing responses; container/SSH session tearing down the pipe.","solutions":["Inspect the joined error text for the underlying OS error (broken pipe, connection reset)","Ensure the client reads all responses and does not close stdout early","Perform a full shutdown/exit handshake before closing the transport","Retry in the client if it was a transient connection issue over a socket-based transport"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = run_session(config, connection).await {\n    // io_threads error with clean main loop: inspect transport cause\n    eprintln!(\"io failure: {e:#}\");\n}","preventionTips":["Do not close the client's read side before consuming all responses","Handle EPIPE/ECONNRESET in wrappers that own the transport","Graceful shutdown before tearing down pipes or sockets"],"tags":["lsp","rust-analyzer","io","pipe"],"backgroundTag":"transport-broken-pipe","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}