tonhowtf/omniget · error · anyhow::Error

Failed to replace

Error message

Failed to replace {}: {}

What it means

Thrown by replace_managed_binary on Windows after the old binary was successfully moved to '<name>.old' but moving the new temp binary into the target position fails. The code rolls back (restores the old file, deletes temp) before returning this error, so the previous binary stays intact.

Solutions

  1. Check free disk space on the target volume and retry.
  2. Check antivirus quarantine/logs for the new binary and add an exclusion.
  3. Verify write permission on the install directory and that the temp file still exists.
  4. Retry the update; the old binary is restored automatically so the app keeps working.
Defensive patterns

Strategy: try-catch

Validate before calling

fn disk_has_space(dir: &std::path::Path, needed: u64) -> bool { /* fs2::available_space(dir) >= needed */ true }

Try / catch

match replace_managed_binary(&temp, &target) {
    Ok(()) => {},
    Err(e) => {
        // library already rolled back to the old binary
        log::error!("replace failed (old binary restored): {e:#}");
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Windows path of replace_managed_binary: fs::rename(temp, target) errors because the target directory became unwritable, disk is full, the temp file was deleted/locked mid-swap, or security software blocked the new executable write.

Common situations: Disk full during update; antivirus quarantining the freshly downloaded binary; permissions changed on the install directory; temp file removed by a cleanup routine during a long download.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/b1fb523d92b92926. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/dependencies.rs:353

        let file_name = target
            .file_name()
            .and_then(|n| n.to_str())
            .unwrap_or("binary")
            .to_string();
        let old = target.with_file_name(format!("{}.old", file_name));
        let _ = std::fs::remove_file(&old);
        if let Err(e) = std::fs::rename(target, &old) {
            let _ = std::fs::remove_file(temp);
            return Err(anyhow!(
                "{} is in use by another process ({}). Wait for active downloads to finish or cancel them, then try again.",
                file_name,
                e
            ));
        }
        if let Err(e) = std::fs::rename(temp, target) {
            let _ = std::fs::rename(&old, target);
            let _ = std::fs::remove_file(temp);
            return Err(anyhow!("Failed to replace {}: {}", file_name, e));
        }
        let _ = std::fs::remove_file(&old);
        Ok(())
    } else {
        std::fs::rename(temp, target)
            .map_err(|e| anyhow!("Failed to replace {}: {}", target.display(), e))?;
        Ok(())
    }
}

pub async fn update_ffmpeg() -> anyhow::Result<PathBuf> {
    if is_flatpak() {
        return Err(anyhow!(
            "FFmpeg is provided by the Flatpak runtime and cannot be updated from inside the app"
        ));
    }
    let path = download_ffmpeg().await?;
    crate::core::ytdlp::reset_ffmpeg_location_cache();

View on GitHub (pinned to 8600b91f42)