{"record":{"id":"ce62e266cc6f0ed6","repo":"lencx/ChatGPT","slug":"view-download-failed-to-get-download-directory","errorCode":null,"errorMessage":"[view:download] Failed to get download directory","messagePattern":"\\[view:download\\] Failed to get download directory","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/core/setup.rs","lineNumber":68,"sourceCode":"            let win_size = core_window\n                .inner_size()\n                .expect(\"[core:window] Failed to get window size\");\n            // Wrap the window in Arc<Mutex<_>> to manage ownership across threads\n            let window = Arc::new(Mutex::new(core_window));\n\n            let main_view =\n                WebviewBuilder::new(\"main\", WebviewUrl::App(\"https://chatgpt.com\".into()))\n                    .auto_resize()\n                    .on_download({\n                        let app_handle = handle.clone();\n                        let download_path = Arc::new(Mutex::new(PathBuf::new()));\n                        move |_, event| {\n                            match event {\n                                DownloadEvent::Requested { destination, .. } => {\n                                    let download_dir = app_handle\n                                        .path()\n                                        .download_dir()\n                                        .expect(\"[view:download] Failed to get download directory\");\n                                    let mut locked_path = download_path\n                                        .lock()\n                                        .expect(\"[view:download] Failed to lock download path\");\n                                    *locked_path = download_dir.join(&destination);\n                                    *destination = locked_path.clone();\n                                }\n                                DownloadEvent::Finished { success, .. } => {\n                                    let final_path = download_path\n                                        .lock()\n                                        .expect(\"[view:download] Failed to lock download path\")\n                                        .clone();\n\n                                    if success {\n                                        app_handle\n                                            .shell()\n                                            .open(final_path.to_string_lossy(), None)\n                                            .expect(\"[view:download] Failed to open file\");\n                                    }","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/lencx/ChatGPT/blob/a6de9a8b61077fa63ad5c3ecbe2bc12e0cb4b4b9/src-tauri/src/core/setup.rs#L50-L86","documentation":"Panic from app_handle.path().download_dir() (tauri::path resolver, backed by the dirs crate) returning Err. The resolver fails when the OS cannot determine the user's download directory: on Linux XDG_DOWNLOAD_DIR is undefined in the user-dirs config, on Windows the known-folder API fails, or the app is sandboxed without the download folder entitlement. This runs inside the WebviewBuilder::on_download callback, so the panic kills the download request handling.","triggerScenarios":"A DownloadEvent::Requested fires (user clicks a download link in the chatgpt.com webview) while download_dir() cannot resolve: minimal Linux distro without xdg-user-dirs installed, XDG_CONFIG_HOME/user-dirs.dirs missing the XDG_DOWNLOAD_DIR line, macOS sandbox/app-translocation blocking the path, HOME unset in the environment.","commonSituations":"Running the app from a clean container/CI or a barebones WM (no xdg-user-dirs); launching via systemd/ssh where HOME or XDG vars are absent; flatpak/sandbox packaging without filesystem permissions; changing the download location in OS settings to an unavailable volume.","solutions":["Use .ok()/if-let and keep the webview-provided default destination instead of redirecting to the download dir, logging a warning","Fall back to an explicit directory, e.g. dirs-style resolution order: download_dir() -> home_dir()/Downloads -> temp dir","On Linux install xdg-user-dirs (or ensure ~/.config/user-dirs.dirs defines XDG_DOWNLOAD_DIR) and confirm $HOME is set when launching","In sandboxed packaging (flatpak/AppImage), grant the download folder permission"],"exampleFix":"// before\nlet download_dir = app_handle\n    .path()\n    .download_dir()\n    .expect(\"[view:download] Failed to get download directory\");\n\n// after\nlet Some(download_dir) = app_handle.path().download_dir().ok() else {\n    eprintln!(\"[view:download] download_dir unavailable; keeping default destination\");\n    return true;\n};","handlingStrategy":"fallback","validationCode":"// probe before the download ever starts, e.g. during setup\nif app_handle.path().download_dir().is_err() {\n    eprintln!(\"[view:download] download_dir unresolvable; downloads will use default destination\");\n}","typeGuard":"fn resolve_download_dir(handle: &tauri::AppHandle) -> Option<std::path::PathBuf> {\n    handle.path().download_dir().ok()\n}","tryCatchPattern":"let Some(download_dir) = app_handle.path().download_dir().ok() else {\n    eprintln!(\"[view:download] download_dir unavailable\");\n    return true; // allow download with webview default destination\n};","preventionTips":["Install xdg-user-dirs on Linux targets and ship it as a package dependency","Never .expect() inside on_download callbacks — a panic there kills the whole download flow","Keep a fallback directory (home/Downloads) resolution order in one helper"],"tags":["tauri","download","paths","linux","xdg","panic"],"backgroundTag":null,"analyzedSha":"a6de9a8b61077fa63ad5c3ecbe2bc12e0cb4b4b9","analyzedAt":"2026-08-16T08:31:13.240Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}