{"record":{"id":"9f44b515b749fc5b","repo":"ramensoftware/windhawk","slug":"file-dialog-message","errorCode":null,"errorMessage":"file dialog: {message}","messagePattern":"file dialog: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/windhawk-core/ui/src/commands/userdata.rs","lineNumber":377,"sourceCode":"        e.to_string(),\n        json!({ \"path\": path.display().to_string() }),\n    ))\n}\n\n/// An over-the-cap archive file as the standard wire error, carrying the failing\n/// `path` like [`io_error`]. Coded and worded like the core's own rejection of an\n/// oversized archive, so which layer caught it does not change what the\n/// front-end shows.\nfn too_large_error(path: &Path, size: u64) -> HostError {\n    HostError::wire(WireError::with_details(\n        ErrorCode::InvalidRequest,\n        format!(\"archive is too large ({size} bytes; the maximum is {MAX_ARCHIVE_BYTES})\"),\n        json!({ \"path\": path.display().to_string() }),\n    ))\n}\n\n/// A file-dialog (COM/shell) failure as an internal wire error.\nfn dialog_error(message: &str) -> HostError {\n    HostError::wire(WireError::new(\n        ErrorCode::Internal,\n        format!(\"file dialog: {message}\"),\n    ))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn format_archive_name_zero_pads_and_reads_as_a_timestamp() {\n        assert_eq!(\n            format_archive_name(2020, 12, 25, 14, 30, 5),\n            \"2020-12-25-14h30m05-windhawk-backup.json\"\n        );\n        // Single-digit month/day/hour are zero-padded so names sort chronologically.\n        assert_eq!(","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk-core/ui/src/commands/userdata.rs#L359-L395","documentation":"dialog_error builds the wire error returned to the Windhawk UI frontend when a native file-dialog (COM/shell) operation fails during import/export of user data. It wraps the OS-level failure message as an ErrorCode::Internal HostError prefixed with 'file dialog:'. The actual cause is whatever COM/shell API reported.","triggerScenarios":"finish_export (saving an archive via a save dialog) or pick_and_read_archive (choosing a file via an open dialog) when the COM IFileDialog call fails — dialog creation failure, user cancellation surfaced as an error, or shell/COM initialization problems.","commonSituations":"Broken or heavily customized shell environments; COM initialization issues in the host process; network/shell namespace locations that fail to enumerate; OS dialog DLL problems after updates.","solutions":["Retry the export/import once — transient shell/COM failures often succeed on a second attempt.","Try again from a standard local folder (e.g. Desktop or Documents) rather than network drives or shell namespace locations.","Check the detailed message after the 'file dialog: ' prefix for the underlying COM error and search that specific HRESULT.","Restart the Windhawk UI process; if persistent, test whether file dialogs work in other apps to rule out a system-wide shell problem."],"exampleFix":"// before\nlet path = pick_and_read_archive(state).map_err(|e| e)?;\n// after\nlet path = match pick_and_read_archive(state) {\n    Ok(p) => p,\n    Err(e) if e.to_string().starts_with(\"file dialog:\") => {\n        return Ok(json!({ \"cancelled\": true })); // treat dialog failure as no-op\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"try-catch","validationCode":"// Raison d'être of dialog_error is OS dialog failure; pre-validate what you can:\n// ensure target directory is writable and check size before export\nlet max_bytes: u64 = 64 * 1024 * 1024;\nif archive_path.metadata()?.len() > max_bytes {\n    return Err(HostError::wire(WireError::new(\n        ErrorCode::InvalidArgument,\n        \"archive too large\".into(),\n    )));\n}","typeGuard":"fn is_dialog_error(e: &HostError) -> bool {\n    e.message.starts_with(\"file dialog: \")\n}","tryCatchPattern":"match export_userdata(state, payload) {\n    Ok(result) => result,\n    Err(e) if e.message.starts_with(\"file dialog: \") => {\n        // surface a friendly message and offer retry, not a crash\n        eprintln!(\"Export failed at the file dialog step: {e}\");\n        retry_or_cancel()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Retry dialog-based operations once before surfacing failure to the user.","Prefer standard local folders over network/shell namespace locations.","Log the full message after the 'file dialog: ' prefix to capture the COM HRESULT.","Keep the shell/COM host thread initialized (CoInitialize) before invoking dialogs."],"tags":["rust","file-dialog","com","windows","ui"],"backgroundTag":"file-open-failed","analyzedSha":"61d99ed8e182e1af1b60109612b6763ad1b4b74e","analyzedAt":"2026-09-12T14:02:41.115Z","contentChangedAt":"2026-09-12T14:02:41.115Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}