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

  1. Read the propagated message — it is the actual main-loop failure
  2. If it is the shutdown-sequence error, fix the client lifecycle (shutdown request then exit notification)
  3. Reproduce with a minimal LSP client to see which event/step failed
  4. 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

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


AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03). Data as JSON: /api/errors/c60f5d8c99990abb. Report an issue: GitHub.