{"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":"error","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/7e623aa83da3776faee50ca4ab9a6c40124acd95/compiler-cli/src/lsp.rs#L30-L66","documentation":"gleam lsp runs over stdio: lsp_server::Connection::stdio() spawns an input thread and an output thread; after LanguageServer::run() completes, io_threads.join().expect(\"joining_lsp_threads\") propagates a panic if either thread panicked. The join error is always a downstream symptom — the real failure is an earlier panic in the message loop (for example an internal compiler invariant hit while processing a didChange request) printed above this one in the editor's LSP log.","triggerScenarios":"The LSP server panicking while handling a specific request (completion, hover, didSave over some edge-case code), stdin/stdout being torn down while a thread is mid-write, or the editor killing the process during shutdown. The join expect then fires as the process unwinds.","commonSituations":"VS Code / Neovim / Helix showing 'gleam language server crashed' or 'server exited unexpectedly'; restart loops when a particular file is open; frequently correlates with a compiler-version regression.","solutions":["Open the editor's LSP log (VS Code: Output panel → Gleam; Neovim: :LspLog) and look for the FIRST panic/stack trace above 'joining_lsp_threads' — that is the actual bug.","Close the file that triggers it, restart the language server / editor to recover.","Update (or pin) the gleam version — LSP panics are fixed frequently, and a mismatch between generated code and server can matter.","Minimize the triggering module and report an issue at github.com/gleam-lang/gleam including the stack trace and `gleam --version`."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Editors: enable automatic LSP restart (VS Code 'server exited unexpectedly' retry; nvim-lspconfig automatic retrigger) so a crash self-heals.","Pin a known-good gleam version per project to avoid regressions that panic the server.","When a crash reproduces on one file, check the LSP log for the FIRST panic above 'joining_lsp_threads' — that backtrace is the actionable one to report."],"tags":["panic","lsp","threads","stdio","language-server","editor-integration"],"backgroundTag":"language-server-crash","analyzedSha":"7e623aa83da3776faee50ca4ab9a6c40124acd95","analyzedAt":"2026-08-17T00:07:02.091Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}