{"record":{"id":"2fc79aa5b1740f89","repo":"janhq/jan","slug":"cannot-resolve-current-exe","errorCode":null,"errorMessage":"cannot resolve current exe","messagePattern":"cannot resolve current exe","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src-tauri/src/bin/jan-cli.rs","lineNumber":720,"sourceCode":"        return all[selection_items[0].0].0.clone();\n    }\n\n    let labels: Vec<String> = selection_items.iter().map(|(_, label)| label.clone()).collect();\n\n    let selection = dialoguer::Select::new()\n        .with_prompt(\"Choose a model\")\n        .items(&labels)\n        .default(0)\n        .interact()\n        .unwrap_or_else(|_| std::process::exit(1));\n\n    all[selection_items[selection].0].0.clone()\n}\n\n// ── Detached spawn ─────────────────────────────────────────────────────────\n\nfn spawn_detached(model_id: &str, args: &ServeArgs) {\n    let exe = std::env::current_exe().expect(\"cannot resolve current exe\");\n\n    // Rebuild argv from ServeArgs fields so we have full control\n    // (avoids needing to filter --detach/-d from the raw OS args).\n    // Use --flag=value format throughout to avoid negative numbers being\n    // misinterpreted as short flags (e.g. --n-gpu-layers -1 → -1 looks like a flag).\n    let mut argv: Vec<String> = vec![\"serve\".into(), model_id.to_string()];\n    if let Some(p) = &args.model_path { argv.push(format!(\"--model-path={p}\")); }\n    if let Some(b) = &args.bin        { argv.push(format!(\"--bin={b}\")); }\n    argv.push(format!(\"--port={}\", args.port));\n    if let Some(m) = &args.mmproj     { argv.push(format!(\"--mmproj={m}\")); }\n    if args.embedding                  { argv.push(\"--embedding\".into()); }\n    argv.push(format!(\"--timeout={}\",      args.timeout));\n    argv.push(format!(\"--n-gpu-layers={}\", args.n_gpu_layers));\n    argv.push(format!(\"--ctx-size={}\",     args.ctx_size));\n    argv.push(format!(\"--threads={}\",      args.threads));\n    if !args.api_key.is_empty()        { argv.push(format!(\"--api-key={}\", args.api_key)); }\n    if args.fit                        { argv.push(\"--fit\".into()); }\n    if args.verbose                    { argv.push(\"--verbose\".into()); }","sourceCodeStart":702,"sourceCodeEnd":738,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/src-tauri/src/bin/jan-cli.rs#L702-L738","documentation":"This is a panic (.expect) from std::env::current_exe() inside spawn_detached(), the function that re-launches the jan CLI binary as a background server process. current_exe() can fail when the OS cannot resolve the running binary's path — on Linux this requires /proc/self/exe to be readable; on macOS it uses _NSGetExecutablePath; on Windows it queries GetModuleFileName. When it fails the process aborts immediately with no recovery.","triggerScenarios":"Running inside a container or chroot where /proc is not mounted (Linux). The executable file was deleted or replaced while the process is running (inode gone). Running under a statically-linked binary in a minimal namespace. Symlink chains that exceed MAX_SYMLINKS. Unusual sandbox environments that block procfs reads.","commonSituations":"CI runners with minimal container images (distroless, scratch). Dev containers or Docker dev environments without /proc. Package managers replacing the binary mid-run during an update. AppImage or Flatpak sandboxes restricting procfs.","solutions":["Ensure /proc is mounted and /proc/self/exe is readable in container/namespace environments.","Avoid deleting or replacing the jan binary while a serve session is running.","For headless/containerized use, set the executable path explicitly via an env var instead of relying on current_exe.","Run `jan serve` directly (non-detached) if detached spawn is not needed."],"exampleFix":"// before\nlet exe = std::env::current_exe().expect(\"cannot resolve current exe\");\n\n// after\nlet exe = std::env::current_exe().unwrap_or_else(|e| {\n    eprintln!(\"Warning: current_exe() failed ({e}), falling back to argv[0]\");\n    std::env::args().next().unwrap_or(\"jan\".into()).into()\n});","handlingStrategy":"fallback","validationCode":"// Before spawning detached, verify the exe is resolvable\nuse std::env;\n\nfn check_exe_resolvable() -> bool {\n    env::current_exe().is_ok()\n}\n\n// In a test or startup check:\nif !check_exe_resolvable() {\n    eprintln!(\"Warning: current_exe() will fail in this environment; detached spawn will crash.\");\n}","typeGuard":null,"tryCatchPattern":"// Replace .expect with a graceful fallback\nlet exe = match std::env::current_exe() {\n    Ok(path) => path,\n    Err(e) => {\n        eprintln!(\"current_exe() failed: {e}\");\n        // Fallback: use argv[0] resolved against PATH\n        let argv0 = std::env::args().next().unwrap_or_else(|| \"jan\".into());\n        which::which(&argv0).unwrap_or_else(|_| PathBuf::from(argv0))\n    }\n};","preventionTips":["Ensure /proc is mounted in container environments.","Do not delete or overwrite the jan binary while a serve session is active.","For containerized use, pass the exe path via an env var as an explicit override.","Add a startup self-test that calls current_exe() and warns if it fails."],"tags":["panic","current-exe","container","detached-process","cli"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}