Hmbown/CodeWhale · error

Codewhale issue-report storage owner is not the current user

Error message

Codewhale issue-report storage owner is not the current user

What it means

`verify_windows_owner_only_handle` reads the security descriptor of the Codewhale issue-report storage and `anyhow::ensure!`s that the descriptor's owner SID equals the current user's SID. When the owner is null or a different account owns the storage, it throws this error. This is a hardening check so private issue reports cannot be read or tampered with by another local account.

Solutions

  1. Take ownership as the current user: `takeown /f <storage-path> /r` then `icacls <storage-path> /setowner %USERNAME%` (run elevated).
  2. Simplest: delete the issue-report storage directory and let the current (non-elevated) Codewhale recreate it with correct ownership.
  3. Avoid running Codewhale elevated for the first-time creation of the storage; run it as the normal user.
  4. If a domain/profile migration changed the SID, recreate the storage under the new profile.

Example fix

// before
# storage created by elevated run, owned by Administrators
# after (run in elevated cmd)
takeown /f "%LOCALAPPDATA%\codewhale\issue-reports" /r
icacls "%LOCALAPPDATA%\codewhale\issue-reports" /setowner %USERNAME% /t
Defensive patterns

Strategy: validation

Validate before calling

# PowerShell pre-check of storage owner before invoking the tool
$p = "$env:LOCALAPPDATA\codewhale\issue-reports"
if (Test-Path $p) {
  $acl = Get-Acl $p
  if ($acl.Owner -ne "$env:USERDOMAIN\$env:USERNAME") {
    Write-Error "storage owned by $($acl.Owner); run: takeown /f $p /r"
  }
}

Type guard

fn storage_owner_is_current_user(path: &std::path::Path) -> bool {
    // on Windows, compare descriptor owner SID to the process user SID;
    // simplest portable proxy: metadata-based ownership check via icacls
    std::process::Command::new("icacls")
        .arg(path)
        .output()
        .map(|o| String::from_utf8_lossy(&o.stdout).contains(&whoami::username()))
        .unwrap_or(false)
}

Try / catch

match report_tool.verify_and_open() {
    Ok(handle) => handle,
    Err(e) if e.to_string().contains("owner is not the current user") => {
        // storage owned by another account: recreate it as this user
        std::fs::remove_dir_all(storage_path)?;
        report_tool.verify_and_open()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the issue-report tool on Windows when the storage file/directory's ACL owner is another user — e.g. the storage was first created by an elevated (admin) process, a different service account, or a profile migration changed ownership.

Common situations: First run under 'Run as administrator' creates the storage owned by Administrators, then a normal user run hits the mismatch; a backup/restore or robocopy copy rewrote ownership; the user account was recreated with a new SID.

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/422d162c3b1226f1. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/github/report.rs:1073

        // SAFETY: the handle remains valid and all output pointers are writable.
        let result = unsafe {
            GetSecurityInfo(
                file.as_raw_handle(),
                SE_FILE_OBJECT,
                OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
                &mut owner,
                std::ptr::null_mut(),
                &mut dacl,
                std::ptr::null_mut(),
                &mut descriptor,
            )
        };
        if result != ERROR_SUCCESS {
            return Err(std::io::Error::from_raw_os_error(result as i32))
                .context("reading Codewhale issue-report security descriptor");
        }
        let _descriptor = WindowsLocalAllocation(descriptor.cast());
        anyhow::ensure!(
            !owner.is_null() && unsafe { EqualSid(owner, user.sid()) } != 0,
            "Codewhale issue-report storage owner is not the current user"
        );
        anyhow::ensure!(
            !dacl.is_null(),
            "Codewhale issue-report storage must have an owner-only DACL"
        );
        let mut count = 0;
        let mut entries: *mut EXPLICIT_ACCESS_W = std::ptr::null_mut();
        // SAFETY: `dacl` belongs to the live descriptor; Windows allocates the
        // returned entry array, released by the guard below.
        let result = unsafe { GetExplicitEntriesFromAclW(dacl, &mut count, &mut entries) };
        if result != ERROR_SUCCESS {
            return Err(std::io::Error::from_raw_os_error(result as i32))
                .context("reading Codewhale issue-report DACL entries");
        }
        let _entries = WindowsLocalAllocation(entries.cast());
        anyhow::ensure!(

View on GitHub (pinned to 73e0f67d83)