astrid-runtime/astrid · error
PermissionDenied
PermissionDenied
Error message
malformed Windows ACL for {description}: {reason} What it means
This error is produced by the malformed() helper in the Windows ACE parser whenever a raw ACE from the OS cannot be decoded safely: wrong length, invalid SID, truncated structure, or an unexpected SID length for the ACE type. It signals a corrupt or hostile security descriptor rather than a policy violation, so it is surfaced as PermissionDenied.
Source
Thrown at crates/astrid-core/src/platform_fs/windows/acl/ace.rs:261
let subauthority_bytes = usize::from(fixed_header[1])
.checked_mul(SID_SUBAUTHORITY_SIZE)
.ok_or_else(|| malformed(description, "the ACE SID length overflowed"))?;
let expected_length = SID_FIXED_HEADER_SIZE
.checked_add(subauthority_bytes)
.ok_or_else(|| malformed(description, "the ACE SID length overflowed"))?;
if expected_length > sid_capacity {
return Err(malformed(
description,
"an access-allowed ACE contains subauthorities beyond its declared size",
));
}
Ok(expected_length)
}
fn malformed(description: &str, reason: &str) -> io::Error {
io::Error::new(
io::ErrorKind::PermissionDenied,
format!("malformed Windows ACL for {description}: {reason}"),
)
}
#[cfg(test)]
mod tests {
use super::*;
use windows_sys::Win32::Security::ACL_REVISION;
use windows_sys::Win32::System::SystemServices::{
ACCESS_ALLOWED_CALLBACK_ACE_TYPE, ACCESS_ALLOWED_OBJECT_ACE_TYPE,
};
#[repr(align(4))]
struct AlignedAce([u8; 64]);
impl AlignedAce {
fn with_header(ace_type: u32, ace_size: u16) -> Self {View on GitHub (pinned to affd8760f4)
Solutions
- Read the descriptor again (the corruption may be transient) with icacls <path> or Get-Acl to see what the OS reports
- Restore the ACL: icacls <path> /reset or reinstall/rewrite the file so a fresh descriptor is created
- Run chkdsk on the volume if descriptors are repeatedly malformed
- If a specific filter/filesystem driver is in the path, exclude the file from it or report the bug to the driver vendor
Defensive patterns
Strategy: try-catch
Validate before calling
// Sanity-check the descriptor before full validation
fn descriptor_readable(path: &std::ffi::OsStr) -> bool {
std::fs::metadata(path).is_ok() // plus a GetNamedSecurityInfoW probe that succeeds
} Try / catch
match validate_trusted_file_acl_handle(&file) {
Err(e) if e.to_string().starts_with("malformed Windows ACL") => {
eprintln!("Corrupt security descriptor; reset ACL or reinstall the file");
}
other => other?,
} Prevention
- Run chkdsk periodically on volumes holding trusted binaries
- Avoid third-party filesystems/filter drivers for install directories
- Reinstall rather than hand-repairing binary files after disk errors
When it happens
Trigger: parse_ace/from_raw reading an ACE header whose declared length does not match the buffer, an SID whose expected_sid_length disagrees with the actual sub-authority count, or any structurally invalid ACE while decoding a file's DACL.
Common situations: Corrupted NTFS security descriptors after disk issues; third-party filesystems or filter drivers returning non-standard ACE layouts; fuzzed or crafted descriptors; buffers truncated by an intermediate API layer.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Windows named-pipe endpoint denied access
- named-pipe has a null or missing DACL
- named-pipe DACL has {ace_count} entries; expected exactly {e
- named-pipe DACL contains a non-canonical access entry
- named-pipe DACL grants an unexpected or duplicate principal
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/a3bbaf20632765e1.
Report an issue: GitHub.