astrid-runtime/astrid · error

InvalidInput

InvalidInput

Error message

staged executable is not on the live executable volume

What it means

An executable replacement requires the staged (temporary) file to live on the same NTFS volume as the live install directory so the final swap can be atomic. prepare_executable_transaction compares volume_root(staged) with the install volume and rejects with InvalidInput when they differ. No files are modified when this fires.

Source

Thrown at crates/astrid-core/src/platform_fs/windows/executable.rs:223

    for name in names {
        let source = extract_dir.join(name);
        extract_guard.verify()?;
        install_guard.verify()?;
        let staged_name = format!(".{name}.{transaction_id}.new");
        let (temporary, new_hash) = stage_transaction_copy_authenticated(
            install_guard,
            extract_guard,
            FileContract::Trusted,
            BoundaryContract::TrustedForCreate,
            install_dir,
            &source,
            &staged_name,
        )?;
        cleanup.track(temporary.clone());
        #[cfg(test)]
        test_maybe_fail_preparation(journal.entries.len())?;
        if volume_root(&temporary)? != install_volume {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "staged executable is not on the live executable volume",
            ));
        }
        let live = install_dir.join(name);
        let had_live = guarded_file_exists(install_guard, &live)?;
        let (rollback, old_hash) = if had_live {
            let rollback_name = format!(".{name}.{transaction_id}.rollback");
            let (rollback_path, old_hash) = stage_transaction_copy_authenticated(
                install_guard,
                install_guard,
                FileContract::Trusted,
                BoundaryContract::TrustedForCreate,
                install_dir,
                &live,
                &rollback_name,
            )?;
            cleanup.track(rollback_path);

View on GitHub (pinned to affd8760f4)

Solutions

  1. Configure the staging/temp location to be on the same volume as the install directory
  2. Verify the install directory is not behind a junction/subst/mapped path that changes its volume root
  3. Canónico the paths (canonicalize) before the call so volume_root computes the intended volume
  4. If cross-volume installs are unavoidable, copy staged bytes into a temporary file on the install volume first

Example fix

// before: staging in %TEMP% on D: while installing to C:\Program Files\App
let staged = temp_dir().join("staged.exe");
// after: stage inside the install volume
let staged = install_dir.join(".staging").join("staged.exe");
Defensive patterns

Strategy: validation

Validate before calling

// Confirm staging and install paths share a volume before the call
fn same_volume(a: &std::path::Path, b: &std::path::Path) -> bool {
    use std::os::windows::ffi::OsStrExt;
    // compare volume root components of canonicalized a and b
    a.canonicalize().ok().zip(b.canonicalize().ok())
        .map(|(a, b)| {
            let av: String = a.components().take(1).map(|c| c.as_os_str().to_string_lossy().into_owned()).collect();
            let bv: String = b.components().take(1).map(|c| c.as_os_str().to_string_lossy().into_owned()).collect();
            av.eq_ignore_ascii_case(&bv)
        }).unwrap_or(false)
}

Try / catch

if !same_volume(&staged, &install_dir) {
    // stage on the install volume first, then call replace_executable_set
}

Prevention

When it happens

Trigger: Calling replace_executable_set with a staged/temporary path or install directory configuration where the staging location resolves to a different volume than the live executable directory (e.g. staging on a temp drive, install on C:).

Common situations: TEMP on a different drive from Program Files; mapped or junctioned install paths whose volume_root differs; container or CI setups mounting install and temp on separate volumes; users relocating the install directory without updating staging config.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/a61998c0dbb770b3. Report an issue: GitHub.