astrid-runtime/astrid · error

named-pipe DACL contains a non-canonical access entry

Error message

named-pipe DACL contains a non-canonical access entry

What it means

While walking the pipe's DACL, each ACE must be an ACCESS_ALLOWED_ACE; anything else (deny ACE, audit ACE, unsupported type) fails this check in validate_pipe_security. The library only recognizes a canonical allow-only ACL, so non-allow entries indicate a foreign or tampered ACL and the connection is refused with PermissionDenied.

Source

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

            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",
            ));
        }
        if unsafe { EqualSid(sid.as_ptr(), current.as_psid()) } != 0 && !saw_current {
            saw_current = true;
        } else if unsafe { EqualSid(sid.as_ptr(), system.as_psid()) } != 0 && !saw_system {
            saw_system = true;
        } else {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "named-pipe DACL grants an unexpected or duplicate principal",

View on GitHub (pinned to affd8760f4)

Solutions

  1. Recreate the pipe via this library so its DACL contains only access-allowed ACEs for the current user and Local System.
  2. Remove the deny/audit ACEs from the pipe's ACL (`Get-Acl` / `Set-Acl` or icacls) in the creating process.
  3. Identify the tool injecting extra ACEs (antivirus, EDR, GPO) and exclude the pipe path from that policy.
  4. Choose a fresh pipe name not covered by existing ACL policy.

Example fix

// before: adding a deny ACE for another user
AddAccessDeniedAceEx(dacl, ..., &other_user_sid);
// after: keep the DACL allow-only; rely on it granting ONLY current user + SYSTEM
AddAccessAllowedAceEx(dacl, ..., GENERIC_ALL, &current_user_sid);
Defensive patterns

Strategy: validation

Validate before calling

// PowerShell preflight: no Deny rules on the pipe
// if ((Get-Acl \\.\pipe\myapp).Access | Where-Object AccessControlType -eq 'Deny') { 'non-canonical ACE present' }

Try / catch

match connect() {
    Err(e) if e.to_string().contains("non-canonical access entry") => {
        eprintln!("pipe ACL contains deny/audit ACEs; recreate the pipe via this library");
    }
    r => r?,
}

Prevention

When it happens

Trigger: connect()/accept() where dacl.ace(index) parses an ACE whose type is not access-allowed, e.g. an ACCESS_DENIED_ACE or SYSTEM_AUDIT_ACE present in the pipe DACL.

Common situations: Hardening tooling or group policy added deny/audit ACEs to the pipe; an admin explicitly denied another account and added a deny entry; the pipe was created by different software with a richer ACL.

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/072b019cbcbb6d84. Report an issue: GitHub.