{"record":{"id":"90668ab3eeb95aa1","repo":"astrid-runtime/astrid","slug":"private-directory-is-not-owned-by-the-current-user","errorCode":null,"errorMessage":"private directory is not owned by the current user: {}","messagePattern":"private directory is not owned by the current user: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/platform_fs.rs","lineNumber":497,"sourceCode":"            },\n            Err(error) => return Err(nix_io_error(error)),\n        };\n        directory = std::fs::File::from(next);\n    }\n    fchmod(&directory, Mode::from_bits_truncate(0o700)).map_err(nix_io_error)?;\n    #[cfg(target_os = \"macos\")]\n    remove_extended_acl_macos(path)?;\n    validate_private_directory_unix(path)\n}\n\n#[cfg(unix)]\nfn validate_private_directory_unix(path: &Path) -> io::Result<()> {\n    use std::os::unix::fs::{MetadataExt as _, PermissionsExt as _};\n\n    let directory = open_directory_no_follow_unix(path)?;\n    let metadata = directory.metadata()?;\n    if metadata.uid() != nix::unistd::getuid().as_raw() {\n        return Err(io::Error::new(\n            io::ErrorKind::PermissionDenied,\n            format!(\n                \"private directory is not owned by the current user: {}\",\n                path.display()\n            ),\n        ));\n    }\n    if metadata.permissions().mode() & 0o777 != 0o700 {\n        return Err(io::Error::new(\n            io::ErrorKind::PermissionDenied,\n            format!(\"private directory is not owner-only: {}\", path.display()),\n        ));\n    }\n    validate_no_extended_acl(path)?;\n    Ok(())\n}\n\n#[cfg(unix)]","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs.rs#L479-L515","documentation":"validate_private_directory_unix requires the private directory to be owned by the current user's uid. Ownership by another user means another account (or root) controls the directory contents, breaking the per-user privacy contract, so it fails with io::ErrorKind::PermissionDenied.","triggerScenarios":"Calling validate_private_directory or ensure_private_directory_unix on a directory whose stat uid differs from getuid() — e.g. a directory created by sudo, restored from another user's backup, or on a shared/multi-user mount.","commonSituations":"Running the app under a different account after creating state with sudo; rsync/tar restores that preserved foreign ownership; shared /home or NFS directories with mixed uids.","solutions":["Reclaim ownership: chown -R $(id -u) ~/.astrid (run as the owner or with sudo).","Avoid creating the directory with sudo; let the target user's process create it.","If a foreign-owned directory is unexpected, remove it and let ensure_private_directory recreate it securely."],"exampleFix":"// before (shell)\nsudo mkdir ~/.astrid\n// after (shell)\nrm -rf ~/.astrid && mkdir ~/.astrid && chmod 700 ~/.astrid   // owned by current user","handlingStrategy":"validation","validationCode":"#[cfg(unix)]\nfn owned_by_me(p: &std::path::Path) -> std::io::Result<bool> {\n    use std::os::unix::fs::MetadataExt;\n    Ok(std::fs::metadata(p)?.uid() == nix::unistd::getuid().as_raw())\n}","typeGuard":"#[cfg(unix)]\nfn current_user_owns(p: &std::path::Path) -> bool {\n    use std::os::unix::fs::MetadataExt;\n    std::fs::symlink_metadata(p)\n        .map(|m| m.uid() == nix::unistd::getuid().as_raw())\n        .unwrap_or(false)\n}","tryCatchPattern":"match validate_private_directory(&dir) {\n    Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {\n        eprintln!(\"run 'chown -R $(id -u) {}' or recreate the directory\", dir.display());\n        return Err(e);\n    }\n    other => other?,\n}","preventionTips":["Never create private state directories with sudo","Fix ownership after rsync/tar restores","Check directory uid once at startup with a clear remediation message"],"tags":["io","filesystem","permissions","ownership","security"],"backgroundTag":"permission-denied","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}