slint-ui/slint · critical

Could not find executable name of the slint-lsp

Error message

Could not find executable name of the slint-lsp

What it means

When the preview-engine feature spawns an embedded live preview as a child process, slint-lsp resolves its own binary path with `std::env::current_exe().expect(...)` to re-invoke itself as `slint-lsp live-preview --remote-controlled`. `current_exe` fails when the OS cannot determine the path of the running executable, and the expect then panics, aborting `main_loop` startup.

Solutions

  1. Ensure /proc is mounted in the container (e.g. mount -t proc proc /proc) so /proc/self/exe is resolvable.
  2. Verify the slint-lsp binary on disk has not been deleted or replaced (deleted-file inode) while the LSP is running; restart from a valid path.
  3. Build/run slint-lsp with the preview-engine child-process requirement avoided: use the embedded preview path or a slint-lsp build/feature configuration that does not spawn `live-preview`.
  4. As a code-level fix, replace the expect with a graceful fallback (e.g. locate the binary via PATH or skip the child-process preview) and log an error instead of panicking.

Example fix

// before
let exe = std::env::current_exe().expect("Could not find executable name of the slint-lsp");

// after
let exe = std::env::current_exe().unwrap_or_else(|e| {
    tracing::error!("cannot resolve own executable ({e}); disabling child preview");
    std::process::exit(1);
});
Defensive patterns

Strategy: validation

Validate before calling

// deployment check before enabling the child-process preview
if !std::path::Path::new("/proc/self/exe").exists() {
    eprintln("/proc unavailable: embedded child preview will fail to spawn");
}

Type guard

fn current_exe_ok() -> bool { std::env::current_exe().is_ok() }

Try / catch

// at startup, resolve once and fail fast with a clear message
let exe = std::env::current_exe()
    .map_err(|e| format!("cannot locate slint-lsp binary for child preview: {e}"))?;

Prevention

When it happens

Trigger: Running slint-lsp in an environment where /proc is unavailable or the binary path is unreadable: deleted binary after exec (Linux), containers/chroots without /proc mounted, some FreeBSD/NetBSD configurations, binaries run from memfd or via unusual exec mechanisms, or restricted permission setups.

Common situations: Docker images that unmount /proc or run with restricted procfs; security sandboxes hiding /proc/self/exe; running the LSP binary from a tmpfs that was cleaned while running; embedding slint-lsp inside a single-binary packer that execs from memory.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at tools/lsp/main.rs:312

) -> Result<()> {
    let request_queue = OutgoingRequestQueue::default();
    #[cfg_attr(not(feature = "preview-engine"), allow(unused))]
    let (preview_to_lsp_sender, preview_to_lsp_receiver) =
        mpsc::unbounded_channel::<PreviewToLspMessage>();

    let server_notifier = ServerNotifier::new(connection.sender.clone(), request_queue.clone());

    #[cfg(not(feature = "preview-engine"))]
    let to_preview = LspToPreviews::with_one(editor_preview::DummyLspToPreview::default());
    #[cfg(feature = "preview-engine")]
    let to_preview = {
        use i_slint_live_preview::protocol::PreviewTarget;

        let sn = server_notifier.clone();

        let child_preview: Box<dyn editor_preview::LspToPreview> =
            Box::new(connector::ChildProcessLspToPreview::new(
                std::env::current_exe().expect("Could not find executable name of the slint-lsp"),
                vec!["live-preview".into(), "--remote-controlled".into()],
                preview_to_lsp_sender.clone(),
            ));
        let embedded_preview: Box<dyn editor_preview::LspToPreview> =
            Box::new(connector::EmbeddedLspToPreview::new(sn.clone()));
        LspToPreviews::new(
            std::collections::HashMap::from([
                (PreviewTarget::ChildProcess, child_preview),
                (PreviewTarget::EmbeddedWasm, embedded_preview),
            ]),
            PreviewTarget::ChildProcess,
            #[cfg(feature = "preview-remote")]
            |to_previews| {
                Rc::new(connector::remote::RemoteLspToPreview::new(
                    preview_to_lsp_sender.clone(),
                    to_previews,
                ))
            },

View on GitHub (pinned to bb937076de)