slint-ui/slint · error

Failed to join adapter thread

Error message

Failed to join adapter thread

What it means

On LSP shutdown, `run_main_loop` joins the dedicated adapter thread that runs the blocking LSP connection handling (`adapter_thread.join().expect("Failed to join adapter thread")`). `join` returns Err only if the joined thread itself panicked, so this expect panics the main loop whenever the adapter thread panicked during handling of LSP messages.

Solutions

  1. Find the root-cause panic: it happened earlier in the adapter thread; scan the log/tracing output for the original panic message and fix that bug.
  2. Update slint-lsp to the latest version — the triggering adapter-thread panic may already be fixed.
  3. Work around operationally by restarting the LSP server/client window after the first panic instead of letting shutdown escalate it.
  4. As a patch, replace the expect with `if adapter_thread.join().is_err() { tracing::error!("adapter thread panicked") }` so shutdown stays graceful.

Example fix

// before
adapter_thread.join().expect("Failed to join adapter thread");

// after
if adapter_thread.join().is_err() {
    tracing::error!("adapter thread panicked before shutdown");
}
Defensive patterns

Strategy: try-catch

Try / catch

match adapter_thread.join() {
    Ok(_) => {},
    Err(_) => tracing::error!("adapter thread panicked; see earlier panic in logs"),
}

Prevention

When it happens

Trigger: The adapter thread panics at any point while processing LSP messages (e.g. an internal expect/assert in message handling, a lock poisoned, index out of bounds on a document), and then the client sends the `shutdown` request, causing the main loop to join the panicked thread.

Common situations: An editor (VS Code, Neovim) sends shutdown after a crash-inducing request; a latent bug in the adapter thread (e.g. handling an unusual document state) panics mid-session and the panic only surfaces at shutdown.

Related errors


AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16). Data as JSON: /api/errors/c141f1127ee4513b. Report an issue: GitHub.

Appendix: source

Thrown at tools/lsp/main.rs:558

        let recompile_idle_timeout = if ctx.session.pending_recompile.is_empty() {
            Duration::MAX
        } else {
            RECOMPILE_IDLE_TIMEOUT
        };
        tokio::select! {
            msg = from_lsp_receiver.recv() => {
                if let Some(msg) = msg {
                    match handle_lsp_message(
                        msg,
                        &connection,
                        &mut rh,
                        &mut ctx,
                        &mut file_watcher
                    ).await
                    {
                        Ok(true) => {
                            tracing::debug!("LSP shutdown requested");
                            adapter_thread.join().expect("Failed to join adapter thread");
                            return Ok(());
                        }
                        Ok(false) => {}
                        Err(e) => tracing::error!("Error handling LSP message: {e}"),
                    }
                } else {
                    adapter_thread.join().expect("Failed to join adapter thread");
                    return Err("LSP connection closed".into());
                }
            }
            _msg = preview_to_lsp_receiver.recv() => {
                // Messages from the native preview come in here:
                #[cfg(feature = "preview-engine")]
                {
                    if let Some(msg) =
                        _msg && let Err(err) = handle_preview_to_lsp_message(msg, &mut ctx).await
                    {
                        tracing::error!("handle_preview_to_lsp_message: {err}");

View on GitHub (pinned to bb937076de)