astrid-runtime/astrid · error

named-pipe DACL has {ace_count} entries; expected exactly {e

Error message

named-pipe DACL has {ace_count} entries; expected exactly {expected_aces}

What it means

The library validates that the pipe's DACL contains exactly the canonical set of ACEs: one allow entry for the current user, plus one for Local System (or just one total when running as Local System). This error means the DACL has a different number of entries (actual count is in the message alongside the expected count), so the pipe's ACL was not created by this library's canonical setup and its access policy cannot be trusted.

Source

Thrown at crates/astrid-core/src/local_transport/windows.rs:943

            "named-pipe has a null or missing DACL",
        ));
    }

    // SAFETY: `dacl` points into the descriptor allocation returned by
    // GetSecurityInfo, which remains live and unmodified through
    // `descriptor_allocation`. The parser validates and bounds the ACL before
    // exposing any borrowed ACE or SID.
    let dacl = unsafe {
        ValidatedAcl::from_raw(
            dacl,
            &descriptor_allocation,
            "named-pipe security descriptor",
        )
    }?;
    let expected_aces = if current.equals(&system) { 1 } else { 2 };
    let ace_count = dacl.ace_count();
    if ace_count != expected_aces {
        return Err(io::Error::new(
            io::ErrorKind::PermissionDenied,
            format!("named-pipe DACL has {ace_count} entries; expected exactly {expected_aces}"),
        ));
    }

    let mut saw_current = false;
    let mut saw_system = current.equals(&system);
    for index in 0..ace_count {
        let ValidatedAce::Allow { flags, mask, sid } = dacl.ace(index)? else {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "named-pipe DACL contains a non-canonical access entry",
            ));
        };
        if flags != 0 || !is_canonical_pipe_full_control(mask) {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "named-pipe DACL contains a non-canonical access entry",

View on GitHub (pinned to affd8760f4)

Solutions

  1. Delete the pipe and let the library recreate it so the canonical 1-or-2-entry DACL is installed.
  2. Compare the ACL with `Get-Acl \\.\pipe\<name>` and remove non-canonical ACEs (extra users/groups) from whatever process creates the pipe.
  3. Check that the process creating the pipe does not apply a custom SECURITY_ATTRIBUTES or inherited ACL; pass SE_DACL_PROTECTED with explicit ACEs only.
  4. If you intentionally added ACEs for other principals, that is unsupported — use a separate pipe or socket variant that permits shared access.

Example fix

// before: adding a group ACE to the pipe DACL
SetNamedSecurityInfoW(handle, ..., dacl_with_extra_group_ace, ...);
// after: leave the DACL exactly as the library created it (current user + SYSTEM only)
// Do not call SetNamedSecurityInfo / icacls on the pipe after creation.
Defensive patterns

Strategy: validation

Validate before calling

// Preflight in PowerShell: count access rules on the pipe
// (Get-Acl \\.\pipe\myapp).Access.Count  # must be 1 (SYSTEM) or 2 (user + SYSTEM)

Try / catch

if let Err(e) = connect() {
    if e.kind() == std::io::ErrorKind::PermissionDenied && e.to_string().contains("expected exactly") {
        // extra ACEs were added after creation; recreate the pipe
        recreate_pipe()?;
    } else { return Err(e.into()); }
}

Prevention

When it happens

Trigger: connect()/accept() on a pipe whose DACL ace_count differs from expected_aces (1 for SYSTEM, 2 otherwise), e.g. extra allow/deny ACEs added after pipe creation.

Common situations: An administrator or group policy added extra ACEs to the pipe; a parent process passed an inheritable ACL that merged in additional entries; the pipe was created by another tool sharing the same name; running the server as SYSTEM but the ACE count logic sees both SIDs equal and expects 1 while the ACL has 2.

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


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