{"record":{"id":"62b6bdc292d7b35a","repo":"lencx/ChatGPT","slug":"view-download-failed-to-open-file","errorCode":null,"errorMessage":"[view:download] Failed to open file","messagePattern":"\\[view:download\\] Failed to open file","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/core/setup.rs","lineNumber":85,"sourceCode":"                                        .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                                    }\n                                }\n                                _ => (),\n                            }\n                            true\n                        }\n                    })\n                    .initialization_script(&AppConf::load_script(&handle, \"ask.js\"))\n                    .initialization_script(INIT_SCRIPT);\n\n            let titlebar_view = WebviewBuilder::new(\n                \"titlebar\",\n                WebviewUrl::App(\"index.html\".into()),\n            )\n            .auto_resize();\n\n            let ask_view =\n                WebviewBuilder::new(\"ask\", WebviewUrl::App(\"index.html\".into()))","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/lencx/ChatGPT/blob/a6de9a8b61077fa63ad5c3ecbe2bc12e0cb4b4b9/src-tauri/src/core/setup.rs#L67-L103","documentation":"Panic from app_handle.shell().open(path, None) (tauri-plugin-shell opener) returning Err when the finished download's file cannot be revealed/opened with the OS default handler. The shell extension delegates to the OS: xdg-open on Linux, open on macOS, ShellExecute on Windows. It fails when the helper binary is missing, the path is invalid (empty PathBuf if Requested never stored a path), or the spawn is blocked by policy/sandbox.","triggerScenarios":"DownloadEvent::Finished { success: true } fires and shell().open() runs with: final_path empty because a Requested event never populated download_path (e.g. download started before this handler existed or the Requested arm returned early), xdg-open absent on a minimal Linux install, the file already deleted/moved, or a sandboxed environment denying process spawn.","commonSituations":"Minimal Linux distros/containers without xdg-utils installed; downloads triggered programmatically or restored webview sessions that skip the Requested event leaving download_path empty; macOS quarantine/permissions blocking open; users annoyed by auto-open behavior on every download.","solutions":["Downgrade the panic to a logged error with if let Err(e) — failure to auto-open should never crash the app","Guard the empty path: skip opening when final_path.as_os_str().is_empty()","On Linux ensure xdg-utils is installed (xdg-open present) or declare it as a dependency","Prefer showing the file in the file manager or a notification instead of auto-opening"],"exampleFix":"// before\napp_handle\n    .shell()\n    .open(final_path.to_string_lossy(), None)\n    .expect(\"[view:download] Failed to open file\");\n\n// after\nif !final_path.as_os_str().is_empty() {\n    if let Err(e) = app_handle\n        .shell()\n        .open(final_path.to_string_lossy(), None)\n    {\n        eprintln!(\"[view:download] Failed to open file: {e}\");\n    }\n}","handlingStrategy":"try-catch","validationCode":"// skip opening when no path was ever recorded (Requested missed)\nif final_path.as_os_str().is_empty() {\n    return true;\n}","typeGuard":"fn openable(p: &std::path::Path) -> bool {\n    !p.as_os_str().is_empty() && p.exists()\n}","tryCatchPattern":"if let Err(e) = app_handle\n    .shell()\n    .open(final_path.to_string_lossy(), None)\n{\n    eprintln!(\"[view:download] Failed to open file: {e}\");\n}","preventionTips":["Ensure xdg-utils (xdg-open) is present on Linux at install time","Treat auto-open as best-effort UX, never a hard requirement of the download flow","Validate the recorded path exists before spawning the OS handler"],"tags":["tauri","shell","opener","linux","xdg-open","download"],"backgroundTag":null,"analyzedSha":"a6de9a8b61077fa63ad5c3ecbe2bc12e0cb4b4b9","analyzedAt":"2026-08-16T08:31:13.240Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}