{"record":{"id":"b803ca47e2e6a0b9","repo":"gleam-lang/gleam","slug":"joining-lsp-threads","errorCode":null,"errorMessage":"joining_lsp_threads","messagePattern":"joining_lsp_threads","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"compiler-cli/src/lsp.rs","lineNumber":48,"sourceCode":"ignore this message.\n\nIf you have run `gleam lsp` yourself in your terminal then exit\nthis program by pressing ctrl+c.\n\"\n        );\n    }\n\n    // Create the transport. Includes the stdio (stdin and stdout) versions but this could\n    // also be implemented to use sockets or HTTP.\n    let (connection, io_threads) = lsp_server::Connection::stdio();\n\n    // Run the server and wait for the two threads to end, typically by trigger\n    // LSP Exit event.\n    LanguageServer::new(&connection, ProjectIO::new())?.run()?;\n\n    // Shut down gracefully.\n    drop(connection);\n    io_threads.join().expect(\"joining_lsp_threads\");\n\n    tracing::info!(\"language_server_stopped\");\n    Ok(())\n}\n\n#[derive(Debug)]\npub struct LspLocker(BuildLock);\n\nimpl LspLocker {\n    pub fn new(paths: &ProjectPaths, target: Target) -> Result<Self> {\n        let build_lock = BuildLock::new_target(paths, Mode::Lsp, target)?;\n        Ok(Self(build_lock))\n    }\n}\n\nimpl Locker for LspLocker {\n    fn lock_for_build(&self) -> Result<LockGuard> {\n        let guard: Guard = self.0.lock(&NullTelemetry)?;","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/gleam-lang/gleam/blob/15b07c783065c92bb016b1b74ed0995a5259850f/compiler-cli/src/lsp.rs#L30-L66","documentation":"After the LSP server exits, the CLI drops the connection and joins the stdio I/O threads with .expect(\"joining_lsp_threads\"). This panics if any of the language-server transport threads ended with an error (e.g. the client closed the pipe abruptly or an I/O error occurred on stdin/stdout).","triggerScenarios":"Running `gleam lsp` and the editor client terminates the connection ungracefully — killing the process, closing stdin mid-message, or an EPIPE on stdout — causing an io_threads.join() Err.","commonSituations":"Editor crashes or is force-quit while gleam lsp is running; language-client restarts that kill the transport; headless/CI usage piping the LSP where the reader closes the pipe early.","solutions":["Shut down the LSP client gracefully (send an Exit notification) before terminating gleam lsp","Restart the language server in the editor; the panic is a teardown-side symptom","Check for broken-pipe conditions (reader process exiting early) in piped setups","If reproducible with a specific editor, file a Gleam issue with client details"],"exampleFix":"// before: force-killing the server\n$ kill -9 $(pgrep 'gleam lsp')\n// after: let the client send Exit, or terminate politely\n$ kill -TERM $(pgrep 'gleam lsp')","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match io_threads.join() {\n    Ok(()) => {},\n    Err(e) => tracing::warn!(error = ?e, \"lsp io thread join failed\"),\n}","preventionTips":["Let the LSP client send Exit before killing the server","Avoid SIGKILL on `gleam lsp`","In piped setups, keep the reader alive until the server exits","Update editor LSP client extensions"],"tags":["lsp","threading","panic","io"],"backgroundTag":"thread-interrupted","analyzedSha":"15b07c783065c92bb016b1b74ed0995a5259850f","analyzedAt":"2026-09-14T11:14:59.388Z","contentChangedAt":"2026-09-14T11:14:59.388Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}