astrid-runtime/astrid · error · io::Error

quarantine to

Error message

quarantine {} to {}: {error}

What it means

When a legacy audit source cannot be migrated in place, quarantine_audit_tree moves the whole tree into the migrations quarantine directory via fs::rename. If the rename fails for any reason, the original OS error is wrapped with this contextual message showing source and destination.

Solutions

  1. Ensure the legacy source and the astrid migrations directory are on the same filesystem, or copy-then-delete instead of rename
  2. Fix permissions on the quarantine root (ensure_private_directory should have created it; check ownership)
  3. Check the wrapped underlying error kind in the message and address it directly (e.g. free disk space, remount rw)
  4. Retry after stopping whatever process holds/removes the source tree

Example fix

// before: rename fails across filesystems
fs::rename(source, &destination).map_err(...)?;
// after: fall back to copy+remove on cross-device errors
if let Err(error) = fs::rename(source, &destination) {
    if error.kind() == io::ErrorKind::CrossesDevices {
        copy_tree(source, &destination)?;
        fs::remove_dir_all(source)?;
    } else { return Err(wrap(error, source, &destination)); }
}
Defensive patterns

Strategy: try-catch

Validate before calling

let quarantine_root = home.migrations_dir().join(QUARANTINE_DIR);
astrid_core::platform_fs::ensure_private_directory(&quarantine_root)?;
// same-device check to avoid EXDEV
dev_of(source)? == dev_of(&quarantine_root)?

Try / catch

match quarantine_audit_tree(&home, &alias, &source) {
    Err(e) if e.kind() == std::io::ErrorKind::CrossesDevices => copy_then_remove(&source)?,
    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => fix_perms_and_retry()? ,
    other => other,
}

Prevention

When it happens

Trigger: handle_non_default_audit_source calls quarantine_audit_tree; fs::rename(source, destination) fails — e.g. source and destination on different filesystems (EXDEV), destination collision beyond unique_destination's attempts, or permission problems.

Common situations: The legacy audit tree lives on a different mount than the astrid home (rename across devices); read-only filesystem; the migrations directory is not writable; the source was concurrently removed.

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 astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/37ddaff20104d770. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-kernel/src/legacy_migration_barrier/legacy_audit.rs:55

    }
    if !path_exists(&path)? {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!(
                "legacy audit source for {alias} was inventoried but is missing: {}",
                path.display()
            ),
        ));
    }
    quarantine_audit_tree(home, alias, &path)
}

fn quarantine_audit_tree(home: &AstridHome, alias: &PrincipalId, source: &Path) -> io::Result<()> {
    let quarantine_root = home.migrations_dir().join(QUARANTINE_DIR);
    astrid_core::platform_fs::ensure_private_directory(&quarantine_root)?;
    let destination = unique_destination(&quarantine_root, alias.as_str())?;
    fs::rename(source, &destination).map_err(|error| {
        io::Error::new(
            error.kind(),
            format!(
                "quarantine {} to {}: {error}",
                source.display(),
                destination.display()
            ),
        )
    })?;
    super::sync_parent(source)?;
    super::sync_parent(&destination)?;
    tracing::warn!(
        principal = %alias,
        destination = %destination.display(),
        "quarantined non-default layout-1 audit tree; bytes preserved"
    );
    Ok(())
}

View on GitHub (pinned to affd8760f4)