rust-lang/rust-analyzer · error
{loop_e}
Error message
{loop_e} What it means
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.
Source
Thrown at crates/rust-analyzer/src/session.rs:167
ShowMessageNotification::METHOD.into(),
ShowMessageParams { kind: MessageType::Warning, message: notice },
);
connection.sender.send(lsp_server::Message::Notification(not)).unwrap();
}
if config.discover_workspace_config().is_none()
&& !config.has_linked_projects()
&& config.detached_files().is_empty()
{
config.rediscover_workspaces();
}
// If the io_threads have an error, there's usually an error on the main
// loop too because the channels are closed. Ensure we report both errors.
match (crate::main_loop(config, connection), io_threads.join()) {
(Err(loop_e), Err(join_e)) => anyhow::bail!("{loop_e}\n{join_e}"),
(Ok(_), Err(join_e)) => anyhow::bail!("{join_e}"),
(Err(loop_e), Ok(_)) => anyhow::bail!("{loop_e}"),
(Ok(_), Ok(_)) => {}
}
tracing::info!("server did shut down");
Ok(())
}
fn patch_path_prefix(path: PathBuf) -> PathBuf {
use std::path::{Component, Prefix};
if cfg!(windows) {
// VSCode might report paths with the file drive in lowercase, but this can mess
// with env vars set by tools and build scripts executed by r-a such that it invalidates
// cargo's compilations unnecessarily. https://github.com/rust-lang/rust-analyzer/issues/14683
// So we just uppercase the drive letter here unconditionally.
// (doing it conditionally is a pain because std::path::Prefix always reports uppercase letters on windows)
let mut comps = path.components();
match comps.next() {
Some(Component::Prefix(prefix)) => {View on GitHub (pinned to e8f7e90aa3)
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
Defensive patterns
Strategy: try-catch
Try / catch
if let Err(e) = run_session(config, connection).await {
match e.to_string().contains("shutdown sequence") {
true => log::info!("client disconnected uncleanly"),
false => log::error!("main loop failed: {e:#}"),
}
} Prevention
- Send shutdown + exit before closing stdin
- Enable RUST_LOG tracing to capture the originating loop failure
- Test integrations with a minimal scripted LSP client
When it happens
Trigger: 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.
Common situations: Editor integration closes stdin without an exit notification; internal server errors surfaced from the loop.
Related errors
- client exited without proper shutdown sequence
- {loop_e} {join_e}
- No file available to rename
- inconsistent text range
- No references found at position
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/c60f5d8c99990abb.
Report an issue: GitHub.