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
- chown the legacy tree to the current user (sudo chown -R $(id -u) <path>) and re-run
- Run the migration as the user that owns the legacy tree
- If the tree belongs to another account intentionally, move it out of this home's migration scope
- 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
- Run migrations as the user who owns the astrid home
- Fix ownership after restores from backups (chown -R)
- Avoid sharing one astrid home across multiple user accounts
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
- legacy source entry is not owned by the current user
- ordinary legacy file is not owned by the current user
- InvalidData
- layout migration source contains a special file
- legacy source entry is group/world writable
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)