Hmbown/CodeWhale · error · io::Error

Codewhale-owned credential file DACL is not…

Error message

Codewhale-owned credential file DACL is not current-user-only

What it means

This error means the Windows discretionary access control list (DACL) on a Codewhale-owned credential file grants access beyond the current user, so the file fails the strict owner-only verification. The library throws it when opening the credential file with require_owner_only=true, after enumerating every ACE and failing to find exactly one access-allowed ACE granting FILE_ALL_ACCESS to the current user's SID via TRUSTEE_IS_SID.

Solutions

  1. Recreate the credential file so Codewhale rewrites it with a current-user-only DACL (delete the file and re-authenticate or re-run the credential setup)
  2. Remove extra ACEs and ensure a single GRANT/SET_ACCESS ACE gives the current user SID FILE_ALL_ACCESS (icacls <file> /inheritance:r /grant:r "%USERNAME%:F")
  3. Copy the file to a fresh location so it inherits a default user-only ACL, then point the config at it

Example fix

// before (broad ACL)
icacls cred.json /grant Users:F
// after
icacls cred.json /inheritance:r /grant:r "%USERNAME%:F"
Defensive patterns

Strategy: validation

Validate before calling

// Windows: check the ACL before relying on the file
use std::os::windows::fs::MetadataExt;
let md = std::fs::metadata(path)?; // plus icacls/SDDL parse if you need full certainty
if !md.permissions().readonly() { /* run: icacls <path> to inspect ACEs */ }

Try / catch

match std::fs::read(path) {
    Ok(data) => use_credential(&data),
    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
        eprintln!("credential file ACL not user-only; re-run credential setup");
        repair_dacl(path);
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling read_codewhale_owned_to_string on a credential file whose DACL was modified (extra ACEs added, permissions narrowed, or trustee expressed as a name rather than SID), so no single ACE matches the current-user-only pattern.

Common situations: File permissions edited manually or by a sync/backup tool that rewrote the ACL; the file was copied from another location preserving broader ACLs; an administrator or installer changed the DACL; the file was created by a different security context.

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 Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/ba9f6fe23668db01. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/external_credentials.rs:505

    }
    let _entries = WindowsLocalAllocation(entries.cast());
    if count != 1 || entries.is_null() {
        return Err(io::Error::new(
            io::ErrorKind::PermissionDenied,
            "Codewhale-owned credential file DACL must grant only one user",
        ));
    }
    // SAFETY: `count == 1` proves the first returned entry is initialized.
    let entry = unsafe { &*entries };
    let trustee_sid: PSID = entry.Trustee.ptstrName.cast();
    // SAFETY: form and null checked in this expression; sid owned by `user`.
    let current_user_only = entry.Trustee.TrusteeForm == TRUSTEE_IS_SID
        && !trustee_sid.is_null()
        && unsafe { EqualSid(trustee_sid, user.sid()) } != 0
        && matches!(entry.grfAccessMode, SET_ACCESS | GRANT_ACCESS)
        && entry.grfAccessPermissions == FILE_ALL_ACCESS;
    if !current_user_only {
        return Err(io::Error::new(
            io::ErrorKind::PermissionDenied,
            "Codewhale-owned credential file DACL is not current-user-only",
        ));
    }
    Ok(())
}

#[cfg(windows)]
struct CurrentWindowsUser {
    token: windows_sys::Win32::Foundation::HANDLE,
    token_info: Vec<usize>,
}

#[cfg(windows)]
impl CurrentWindowsUser {
    fn open() -> io::Result<Self> {
        use windows_sys::Win32::Foundation::{GetLastError, HANDLE};
        use windows_sys::Win32::Security::{

View on GitHub (pinned to 73e0f67d83)