{"record":{"id":"49806929015d39bb","repo":"astrid-runtime/astrid","slug":"private-file-is-not-owner-only","errorCode":null,"errorMessage":"private file is not owner-only: {}","messagePattern":"private file is not owner-only: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/platform_fs.rs","lineNumber":557,"sourceCode":"    let file = open_file_no_follow_unix(path)?;\n    let metadata = fstat(&file).map_err(nix_io_error)?;\n    if metadata.st_mode & 0o170_000 != 0o100_000 {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"private path is not a regular file: {}\", path.display()),\n        ));\n    }\n    if metadata.st_uid != nix::unistd::getuid().as_raw() {\n        return Err(io::Error::new(\n            io::ErrorKind::PermissionDenied,\n            format!(\n                \"private file is not owned by the current user: {}\",\n                path.display()\n            ),\n        ));\n    }\n    if metadata.st_mode & 0o777 != 0o600 {\n        return Err(io::Error::new(\n            io::ErrorKind::PermissionDenied,\n            format!(\"private file is not owner-only: {}\", path.display()),\n        ));\n    }\n    if metadata.st_nlink != 1 {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\n                \"private file has {} links; durable media must have exactly one\",\n                metadata.st_nlink\n            ),\n        ));\n    }\n    validate_no_extended_acl(path)?;\n    Ok(())\n}\n\n#[cfg(target_os = \"macos\")]","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs.rs#L539-L575","documentation":"A private file must have mode exactly 0600 (owner read/write, no group/other bits). The library throws this when validation finds st_mode & 0o777 != 0o600, because looser permissions would expose security-sensitive content to other local users.","triggerScenarios":"validate_private_file sees a file with e.g. 0644, 0664, or 0666 permissions. Happens when the file was created outside the library, copied with permissions preserved, or had permissions loosened after creation.","commonSituations":"rsync/scp/tar copies preserving 0644; a umask of 0022 applied when another tool created the file; editor or backup tool rewrote the file with default perms; restoring from a backup with relaxed modes.","solutions":["Chmod the file to owner-only: `chmod 600 <path>`.","Call the library's restrict_private_file, which fchmods the file to 0600 and revalidates.","Delete and recreate the file through the library so it is created with 0600.","Ensure any external tooling that rewrites the file also sets 0600 (set umask 077 or explicit chmod in scripts)."],"exampleFix":"// before (file has 0644)\nvalidate_private_file(Path::new(\"/home/me/.astrid/credentials\"))?;\n// after (fix mode first)\n// $ chmod 600 /home/me/.astrid/credentials\nvalidate_private_file(Path::new(\"/home/me/.astrid/credentials\"))?;","handlingStrategy":"validation","validationCode":"use std::os::unix::fs::PermissionsExt;\nfn mode_is_600(path: &std::path::Path) -> bool {\n    std::fs::metadata(path).map(|m| m.permissions().mode() & 0o777 == 0o600).unwrap_or(false)\n}","typeGuard":"fn is_owner_only(path: &std::path::Path) -> bool {\n    std::fs::metadata(path)\n        .map(|m| m.permissions().mode() & 0o777 == 0o600)\n        .unwrap_or(false)\n}","tryCatchPattern":"if let Err(e) = validate_private_file(path) {\n    if e.kind() == std::io::ErrorKind::PermissionDenied {\n        std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600))?;\n    } else { return Err(e.into()); }\n}","preventionTips":["Run with umask 077 in scripts that touch private files","chmod 600 after any external tool rewrites the file","Preserve modes carefully when restoring backups"],"tags":["filesystem","unix","permissions","chmod"],"backgroundTag":"file-write-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"}