{"record":{"id":"c60f5d8c99990abb","repo":"rust-lang/rust-analyzer","slug":"loop-e","errorCode":null,"errorMessage":"{loop_e}","messagePattern":"\\{loop_e\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/rust-analyzer/src/session.rs","lineNumber":167,"sourceCode":"            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() {\n            Some(Component::Prefix(prefix)) => {","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/rust-analyzer/src/session.rs#L149-L185","documentation":"Same `run_session` error handling for the case where the IO threads finished fine but `main_loop` itself returned an error (e.g. the 'client exited without proper shutdown sequence' bail). The single underlying loop error is propagated verbatim.","triggerScenarios":"Calling `run_session` where `io_threads.join()` succeeds but `main_loop` returns `Err` — most commonly the missing-shutdown bail from the main loop, or any error propagated out of event handling.","commonSituations":"Editor integration closes stdin without an exit notification; internal server errors surfaced from the loop.","solutions":["Read the propagated message — it is the actual main-loop failure","If it is the shutdown-sequence error, fix the client lifecycle (shutdown request then exit notification)","Reproduce with a minimal LSP client to see which event/step failed","Check rust-analyzer logs (RUST_LOG=info or error) for the originating failure"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = run_session(config, connection).await {\n    match e.to_string().contains(\"shutdown sequence\") {\n        true => log::info!(\"client disconnected uncleanly\"),\n        false => log::error!(\"main loop failed: {e:#}\"),\n    }\n}","preventionTips":["Send shutdown + exit before closing stdin","Enable RUST_LOG tracing to capture the originating loop failure","Test integrations with a minimal scripted LSP client"],"tags":["lsp","rust-analyzer","shutdown","main-loop"],"backgroundTag":"lsp-shutdown-protocol-violation","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"}