astrid-runtime/astrid · error
private path has an extended access-control list
Error message
private path has an extended access-control list
What it means
On macOS, private paths must not carry extended ACL entries beyond the standard POSIX mode bits. validate_no_extended_acl_macos parses `ls -lde` output and throws this when any numbered ACL entry is present, since extra ACL grants can silently widen access even when the mode is 0600.
Source
Thrown at crates/astrid-core/src/platform_fs.rs:612
let output = std::process::Command::new("/bin/ls")
.arg("-lde")
.arg(path)
.env("LC_ALL", "C")
.output()?;
if !output.status.success() {
return Err(io::Error::other(
"failed to inspect extended access-control list",
));
}
let listing = String::from_utf8(output.stdout)
.map_err(|_| io::Error::other("access-control listing is not UTF-8"))?;
let has_acl_entry = listing.lines().skip(1).any(|line| {
line.trim_start()
.split_once(':')
.is_some_and(|(index, _)| index.parse::<usize>().is_ok())
});
if has_acl_entry {
Err(io::Error::new(
io::ErrorKind::PermissionDenied,
"private path has an extended access-control list",
))
} else {
Ok(())
}
}
#[cfg(target_os = "macos")]
fn absolute_command_path(path: &Path) -> io::Result<PathBuf> {
if path.is_absolute() {
Ok(path.to_path_buf())
} else {
Ok(std::env::current_dir()?.join(path))
}
}
#[cfg(unix)]View on GitHub (pinned to affd8760f4)
Solutions
- Strip ACLs from the file/directory: `chmod -N <path>` (and `chmod -RN <dir>` recursively).
- Recreate the file/directory through the library, which runs chmod -N automatically on restrict/ensure paths.
- Move the private directory out of a parent folder with inherited ACLs (e.g. ~/Library CloudStorage) to a plain home path.
- Inspect with `ls -lde <path>` to confirm no numbered ACL entries remain before retrying.
Example fix
// before (macOS, file has inherited ACL entries)
validate_private_file(Path::new("/Users/me/.astrid/credentials"))?;
// after
// $ chmod -N /Users/me/.astrid/credentials
validate_private_file(Path::new("/Users/me/.astrid/credentials"))?; Defensive patterns
Strategy: validation
Validate before calling
fn has_no_macos_acl(path: &std::path::Path) -> std::io::Result<bool> {
let out = std::process::Command::new("/bin/ls")
.args(["-lde"]).arg(path).env("LC_ALL", "C").output()?;
let text = String::from_utf8_lossy(&out.stdout);
Ok(!text.lines().skip(1).any(|l| l.trim_start().split_once(':')
.is_some_and(|(i, _)| i.parse::<usize>().is_ok())))
} Try / catch
match validate_private_file(path) {
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied
&& e.to_string().contains("access-control list") => {
let _ = std::process::Command::new("/bin/chmod").args(["-N"]).arg(path).status()?;
},
other => other?,
} Prevention
- Run `chmod -N` on files restored from backups or Finder copies
- Keep private state out of ACL-inheriting folders (cloud sync dirs)
- Check `ls -lde` on macOS when validation fails
When it happens
Trigger: validate_private_directory or validate_private_file is called on macOS and the target has ACL entries (visible as lines like ` 0: group:everyone deny delete` in `ls -lde`).
Common situations: Files restored from backups or Finder copies that carried ACLs; files created under a directory with inherited ACLs; files synced from cloud-drive folders that attach quarantine/ACL entries.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
- trusted Windows parent has a null DACL: {description}
- leftover capsule authority receipt is not a regular file: {}
- legacy capsule authority root is not a regular directory: {}
- legacy capsule authority root contains a non-regular entry:
- legacy capsule authority root is not a regular directory: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/8611fcb29c42f365.
Report an issue: GitHub.