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

  1. Strip ACLs from the file/directory: `chmod -N <path>` (and `chmod -RN <dir>` recursively).
  2. Recreate the file/directory through the library, which runs chmod -N automatically on restrict/ensure paths.
  3. Move the private directory out of a parent folder with inherited ACLs (e.g. ~/Library CloudStorage) to a plain home path.
  4. 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

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


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