janhq/jan · critical
Failed to get current exe path
Error message
Failed to get current exe path
What it means
This is a panic (.expect) from env::current_exe() inside schedule_mcp_start_task, which prepares to launch a stdio-based MCP server as a child process using the jan binary's directory as the working path. current_exe() fails under the same conditions as in spawn_detached: missing /proc on Linux, deleted binary inode, sandbox restrictions.
Source
Thrown at src-tauri/src/core/mcp/helpers.rs:404
}
Ok(())
}
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() {View on GitHub (pinned to fad3f12a14)
Solutions
- Ensure /proc/self/exe is accessible in the runtime environment.
- Avoid replacing the jan binary while MCP servers are being spawned.
- Cache the exe path at startup rather than re-resolving it per MCP server start.
- Fall back to std::env::current_dir().join(argv[0]) when current_exe fails.
Example fix
// before
let exe_path = env::current_exe().expect("Failed to get current exe path");
// after
let exe_path = env::current_exe().unwrap_or_else(|e| {
log::warn!("current_exe() failed ({e}); using argv[0] fallback");
PathBuf::from(std::env::args().next().unwrap_or_default())
}); Defensive patterns
Strategy: fallback
Validate before calling
// At startup, cache the exe path so MCP start tasks don't need current_exe
use std::sync::OnceLock;
static EXE_PATH: OnceLock<PathBuf> = OnceLock::new();
pub fn init_exe_path() {
let _ = EXE_PATH.get_or_init(|| {
std::env::current_exe().unwrap_or_else(|e| {
log::warn!("current_exe failed at init: {e}");
PathBuf::from(std::env::args().next().unwrap_or_default())
})
});
}
pub fn get_cached_exe_path() -> &'static PathBuf {
EXE_PATH.get().expect("init_exe_path not called")
} Try / catch
// Replace .expect with a fallback
let exe_path = match env::current_exe() {
Ok(p) => p,
Err(e) => {
log::error!("current_exe() failed: {e}; MCP server spawn may fail");
return Err(format!("Cannot resolve executable path: {e}"));
}
}; Prevention
- Cache the exe path at app startup rather than resolving per MCP server start.
- Ensure /proc is mounted in container environments.
- Fall back to argv[0] resolved via PATH when current_exe fails.
- Log the exe path at startup so failures are diagnosable.
When it happens
Trigger: Starting an MCP server configured with command 'npx' or a local binary while running in a container without /proc. The jan binary was replaced by an updater while MCP servers are being initialized. Running in a minimal namespace/jail that blocks procfs.
Common situations: AppImage or Flatpak sandboxes. Docker dev containers without procfs. Post-update first launch where the old binary path no longer exists. SELinux denying readlink on /proc/self/exe.
Related errors
- cannot resolve current exe
- Failed to determine the home directory
- Failed to serialize MCP settings
- Executable must have a parent directory
- Failed to get app data dir
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/b10a86531b2f6096.
Report an issue: GitHub.