janhq/jan · warning

Executable must have a parent directory

Error message

Executable must have a parent directory

What it means

This is a panic (.expect) from Path::parent() on the exe path obtained from current_exe(). parent() returns None only when the path is a bare root or a single component with no directory separator. Since current_exe() returns absolute paths on all supported platforms, this panic is effectively unreachable in practice — it exists as a safety invariant assertion.

Source

Thrown at src-tauri/src/core/mcp/helpers.rs:407

        }
        Err(e) => {
            log::error!("Failed to start MCP server {name} on first attempt: {e}");
            Err(e)
        }
    }
}

async fn schedule_mcp_start_task<R: Runtime>(
    app: tauri::AppHandle<R>,
    servers: SharedMcpServers,
    name: String,
    config: Value,
) -> Result<(), String> {
    let app_path = get_jan_data_folder_path(app.clone());
    let exe_path = env::current_exe().expect("Failed to get current exe path");
    let exe_parent_path = exe_path
        .parent()
        .expect("Executable must have a parent directory");
    let bin_path = exe_parent_path.to_path_buf();

    let config_params = extract_command_args(&config)
        .ok_or_else(|| format!("Failed to extract command args from config for {name}"))?;

    if let (Some("http"), Some(url)) = (
        config_params.transport_type.as_deref(),
        config_params.url.clone(),
    ) {
        let transport = StreamableHttpClientTransport::with_client(
            reqwest::Client::builder()
                .default_headers({
                    // Map envs to request headers
                    let mut headers: tauri::http::HeaderMap = reqwest::header::HeaderMap::new();
                    for (key, value) in config_params.headers.iter() {
                        if let Some(v_str) = value.as_str() {
                            // Try to map env keys to HTTP header names (case-insensitive)
                            // Most HTTP headers are Title-Case, so we try to convert

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Replace .expect with unwrap_or to fall back to the current directory.
  2. Log a warning and use std::env::current_dir() if parent is None.
  3. This is a defensive assertion — no user action is needed unless it actually fires.

Example fix

// before
let exe_parent_path = exe_path.parent().expect("Executable must have a parent directory");

// after
let exe_parent_path = exe_path.parent().unwrap_or_else(|| {
    log::warn!("exe path has no parent; using current dir");
    std::env::current_dir().unwrap_or_default().as_path()
});
Defensive patterns

Strategy: fallback

Validate before calling

// Validate the exe path has a parent before using it
fn exe_parent_or_cwd(exe: &Path) -> PathBuf {
    exe.parent()
        .map(|p| p.to_path_buf())
        .unwrap_or_else(|| {
            log::warn!("exe path has no parent component: {}", exe.display());
            std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
        })
}

Try / catch

// Replace .expect with a fallback
let bin_path = match exe_path.parent() {
    Some(p) => p.to_path_buf(),
    None => {
        log::warn!("exe path has no parent; using current working directory");
        std::env::current_dir().unwrap_or_default()
    }
};

Prevention

When it happens

Trigger: current_exe() somehow returns a path like "/" or a bare filename with no directory component. A custom platform or exotic FS where the path representation lacks a parent. Theoretically impossible on standard Linux/macOS/Windows where current_exe always yields a full path.

Common situations: Not encountered in real usage. Would only manifest on deeply unusual platforms or after a std library bug. Listed here for completeness.

Related errors


AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12). Data as JSON: /api/errors/94395e749f508211. Report an issue: GitHub.