{"record":{"id":"02d63b8ee386b89e","repo":"tonhowtf/omniget","slug":"failed-to-replace-file-after-3-attempts","errorCode":null,"errorMessage":"Failed to replace file after 3 attempts: {}","messagePattern":"Failed to replace file after 3 attempts: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/ffmpeg.rs","lineNumber":558,"sourceCode":"    let mut rename_ok = false;\n    for attempt in 0..3 {\n        match std::fs::rename(&temp_output, file) {\n            Ok(()) => {\n                rename_ok = true;\n                break;\n            }\n            Err(e) if attempt < 2 => {\n                tracing::warn!(\n                    \"Failed to replace file (attempt {}): {}, retrying...\",\n                    attempt + 1,\n                    e\n                );\n                tokio::time::sleep(std::time::Duration::from_millis(500 * (attempt as u64 + 1)))\n                    .await;\n            }\n            Err(e) => {\n                let _ = std::fs::remove_file(&temp_output);\n                return Err(anyhow!(\"Failed to replace file after 3 attempts: {}\", e));\n            }\n        }\n    }\n    if !rename_ok {\n        let _ = std::fs::remove_file(&temp_output);\n        return Err(anyhow!(\"Failed to replace file\"));\n    }\n\n    Ok(())\n}\n\nasync fn download_thumbnail(\n    client: &reqwest::Client,\n    url: &str,\n    dest_dir: &Path,\n) -> anyhow::Result<std::path::PathBuf> {\n    let response = client\n        .get(url)","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/ffmpeg.rs#L540-L576","documentation":"embed_metadata() renames the temp output over the original file, retrying up to 3 times with backoff. If a rename attempt fails with a hard error (not a transient sharing violation that the retry loop tolerates), the temp file is deleted and this error returns the underlying io::Error.","triggerScenarios":"Calling embed_metadata when the destination file is locked by another process with incompatible sharing semantics, or the destination directory lacks write permission and the retry loop's Err branch is hit (as opposed to the Ok-but-failed path).","commonSituations":"Another app (player, antivirus, cloud sync) holding the output file open on Windows; read-only target directory; the temp file living on a different filesystem than the destination in exotic setups.","solutions":["Close any program using the output file (media player, editor) and retry the embedding.","Check the destination directory is writable by the app's user.","Add the wrapped io::Error detail to logs to see if it's PermissionDenied vs cross-device.","As a workaround, write the embedded-metadata file next to the original under a new name instead of replacing it."],"exampleFix":"// before\nErr(e) => {\n    let _ = std::fs::remove_file(&temp_output);\n    return Err(anyhow!(\"Failed to replace file after 3 attempts: {}\", e));\n}\n// after\nErr(e) => {\n    let _ = std::fs::remove_file(&temp_output);\n    return Err(anyhow!(\n        \"Failed to replace file after 3 attempts: {} (is another program using the output file?)\",\n        e\n    ));\n}","handlingStrategy":"retry","validationCode":"// detect an open handle on Windows-style platforms before embedding\nlet can_write = std::fs::OpenOptions::new()\n    .append(true)\n    .open(file)\n    .is_ok();\nif !can_write {\n    return Err(\"output file is locked by another process; close it and retry\".into());\n}","typeGuard":null,"tryCatchPattern":"match embed_metadata(/* ... */).await {\n    Err(e) if e.to_string().contains(\"Failed to replace file after 3 attempts\") => {\n        ui::notify_file_locked(file); // prompt user to close players/sync apps\n        // optionally schedule a retry after a delay\n    }\n    other => other?,\n}","preventionTips":["Close media players/sync clients that hold the output file open","Ensure the download directory is writable by the app's user","Keep temp file and destination on the same filesystem for atomic rename"],"tags":["ffmpeg","file-rename","file-lock","windows"],"backgroundTag":"file-write-failed","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}