{"record":{"id":"64191cc27b43f324","repo":"rust-lang/rust-analyzer","slug":"client-exited-without-proper-shutdown-sequence","errorCode":null,"errorMessage":"client exited without proper shutdown sequence","messagePattern":"client exited without proper shutdown sequence","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/rust-analyzer/src/main_loop.rs","lineNumber":205,"sourceCode":"                .map(|f| format!(\"**/{f}\"));\n            self.register_did_save_capability(additional_patterns);\n        }\n\n        if self.config.discover_workspace_config().is_none() {\n            self.fetch_workspaces_queue.request_op(\n                \"startup\".to_owned(),\n                FetchWorkspaceRequest { path: None, force_crate_graph_reload: false },\n            );\n            if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =\n                self.fetch_workspaces_queue.should_start_op()\n            {\n                self.fetch_workspaces(cause, path, force_crate_graph_reload);\n            }\n        }\n\n        while let Ok(event) = self.next_event(&inbox) {\n            let Some(event) = event else {\n                anyhow::bail!(\"client exited without proper shutdown sequence\");\n            };\n            if matches!(\n                &event,\n                Event::Lsp(lsp_server::Message::Notification(Notification { method, .. }))\n                if method == lsp_types::ExitNotification::METHOD.as_str()\n            ) {\n                return Ok(());\n            }\n            self.handle_event(event);\n        }\n\n        Err(anyhow::anyhow!(\"A receiver has been dropped, something panicked!\"))\n    }\n\n    fn register_did_save_capability(&mut self, additional_patterns: impl Iterator<Item = String>) {\n        let additional_filters = additional_patterns.map(|pattern| {\n            lsp_types::DocumentFilter::TextDocumentFilter(lsp_types::TextDocumentFilter::Pattern(\n                lsp_types::TextDocumentFilterPattern {","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/rust-analyzer/src/main_loop.rs#L187-L223","documentation":"rust-analyzer's main loop reads events from the LSP connection. When the event channel closes (client's stdio/socket ends) without the client first sending an `exit` notification after `shutdown`, the loop treats this as a protocol violation and aborts with this error instead of exiting cleanly. It enforces the LSP lifecycle: clients must not just drop the connection.","triggerScenarios":"The client (editor) closes its end of the connection (closes stdin or kills the process pipe) while `run` is waiting on `next_event`, and no `shutdown` request + `exit` notification sequence was completed beforehand, so `next_event` returns `None`.","commonSituations":"Editor crashes or is force-killed; a wrapper script kills the server with SIGKILL instead of issuing an LSP shutdown; pipes are broken by the parent process exiting; misconfigured clients that terminate the transport abruptly.","solutions":["Fix the client/editor integration to send a `shutdown` request followed by an `exit` notification before closing stdio","Check for client crashes: if the editor was killed, this error is expected fallout of the abrupt termination and can be ignored in logs","If you manage rust-analyzer programmatically, terminate gracefully by writing a `shutdown`/`exit` pair, then close stdin","Update rust-analyzer/client versions to match, since protocol mismatches between old clients and new servers can break the lifecycle"],"exampleFix":"// client-side, before closing the process\n// before\nchild.stdin.close();\n// after\nsend_request(\"shutdown\", None);\nsend_notification(\"exit\", None);\nchild.stdin.close();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// client side: treat this as expected on abrupt kill\nmatch server.wait() {\n    Err(e) if e.to_string().contains(\"without proper shutdown sequence\") => {\n        // client was killed uncleanly; log at info level, not error\n    }\n    other => other?,\n}","preventionTips":["Always send shutdown request then exit notification before closing the transport","Never SIGKILL the server in tooling; prefer graceful LSP shutdown","Keep client and rust-analyzer versions in sync"],"tags":["lsp","rust-analyzer","shutdown","protocol"],"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"}