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

PermissionDenied

PermissionDenied

Error message

legacy dedicated source is not owned by the current user: {}

What it means

Before tightening permissions on a legacy dedicated tree, the current user must own it (unix). If the directory's uid differs from the process uid, the function raises PermissionDenied rather than chmod-ing someone else's directory, which could break other users' data or fail midway.

Solutions

  1. chown the legacy tree to the current user (sudo chown -R $(id -u) <path>) and re-run
  2. Run the migration as the user that owns the legacy tree
  3. If the tree belongs to another account intentionally, move it out of this home's migration scope
  4. Fix backup/restore tooling to preserve or correct ownership for the owning user

Example fix

// before: directory owned by root, migration runs as user
// after
sudo chown -R $(id -u):$(id -g) ~/.local/share/astrid/legacy-dedicated
Defensive patterns

Strategy: try-catch

Validate before calling

#[cfg(unix)]
{
    use std::os::unix::fs::MetadataExt;
    let md = std::fs::symlink_metadata(path)?;
    if md.uid() != nix::unistd::getuid().as_raw() {
        // chown or switch user before calling the API
    }
}

Try / catch

if let Err(e) = tighten_legacy_dedicated_directories(&home) {
    if e.kind() == std::io::ErrorKind::PermissionDenied
        && e.to_string().contains("not owned by the current user") {
        eprintln!("chown the tree to the current user and retry");
    }
}

Prevention

When it happens

Trigger: tighten_dedicated_tree (called by tighten_legacy_dedicated_directories) runs on unix; metadata.uid() != nix::unistd::getuid().as_raw() for the inspected directory.

Common situations: The legacy directory was created by root or another service account and the migration runs as the regular user; files were restored from a backup preserving foreign ownership; a shared multi-user machine hosts the home directory.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

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

        Ok(metadata) => metadata,
        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
        Err(error) => return Err(error),
    };
    if metadata.file_type().is_symlink() || !metadata.is_dir() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!(
                "legacy dedicated source is not a regular directory: {}",
                path.display()
            ),
        ));
    }
    astrid_core::platform_fs::verify_no_redirects(path)?;
    #[cfg(unix)]
    {
        use std::os::unix::fs::MetadataExt as _;
        if metadata.uid() != nix::unistd::getuid().as_raw() {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                format!(
                    "legacy dedicated source is not owned by the current user: {}",
                    path.display()
                ),
            ));
        }
    }
    astrid_core::platform_fs::ensure_private_directory(path)?;
    for entry in fs::read_dir(path)? {
        let entry = entry?;
        let child = entry.path();
        let child_metadata = fs::symlink_metadata(&child)?;
        if child_metadata.file_type().is_symlink() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "legacy dedicated source contains a redirect: {}",

View on GitHub (pinned to affd8760f4)