ramensoftware/windhawk · error · SettingsError

RegQueryValueEx (data)

Error message

RegQueryValueEx (data)

What it means

The second (sized) RegQueryValueExW call inside query_raw failed with an OS error other than ERROR_SUCCESS. The size query succeeded but reading the actual data buffer failed; the error carries the Win32 function name and the OS error code.

Solutions

  1. Retry query_raw once; a transient size race typically resolves on the second read.
  2. Check the wrapped OS code (ERROR_MORE_DATA implies the value grew — retry with a larger buffer).
  3. Ensure the key handle is still valid and opened with KEY_QUERY_VALUE access.
  4. Serialize writes/reads (avoid concurrent writers to the same value) if a race is suspected.

Example fix

// before
let (t, data) = settings.query_raw(name)?; // can fail transiently
// after
let mut tries = 0;
let (t, data) = loop {
    match settings.query_raw(name) {
        Ok(v) => break v,
        Err(e) if tries < 2 => { tries += 1; continue; }
        Err(e) => return Err(e),
    }
};
Defensive patterns

Strategy: retry

Validate before calling

// no pre-call validation; failure is environmental or a size race

Try / catch

let mut tries = 0;
let val = loop {
    match settings.get_string("x") {
        Ok(v) => break v,
        Err(e) if tries < 2 && e.message().contains("RegQueryValueEx") => { tries += 1; continue; }
        Err(e) => return Err(e),
    }
};

Prevention

When it happens

Trigger: Reading a value whose size changed or grew between the size probe and the data read (a race with another writer), an access-denied on the data read, or a handle invalidated mid-read.

Common situations: Another process concurrently rewriting the value; very large values where the size probe and read race; transient registry access issues under restrictive policies.

Related errors


AI-assisted analysis of ramensoftware/windhawk@61d99ed8e1 (2026-09-12). Data as JSON: /api/errors/99f6886e4593d97a. Report an issue: GitHub.

Appendix: source

Thrown at src/windhawk-core/windows/src/registry.rs:444

        }
        let mut buf = vec![0u8; size as usize];
        let mut data_size = size;
        // SAFETY: buf has data_size bytes; out params valid.
        let rc = unsafe {
            RegQueryValueExW(
                hkey,
                name_w.as_ptr(),
                std::ptr::null(),
                &mut value_type,
                buf.as_mut_ptr(),
                &mut data_size,
            )
        };
        if rc == ERROR_FILE_NOT_FOUND {
            return Ok(None);
        }
        if rc != ERROR_SUCCESS {
            return Err(self.err("get", rc, "RegQueryValueEx (data)"));
        }
        buf.truncate(data_size as usize);
        Ok(Some((value_type, buf)))
    }

    fn set_raw(&self, name: &str, value_type: u32, data: &[u8]) -> Result<(), SettingsError> {
        self.check_name("set", name)?;
        let Some(hkey) = self.hkey() else {
            return Err(self.err("set", 0, "set on a read-only/absent key"));
        };
        let name_w = to_wide(name);
        // A length the API's u32 cannot hold has no honest value to pass, and a
        // clamped one would hand the call a length the buffer does not have.
        let len = u32::try_from(data.len())
            .map_err(|_| self.err("set", 0, "value is too large for the registry"))?;
        // SAFETY: name_w is NUL-terminated; data/len describe a valid buffer.
        let rc =
            unsafe { RegSetValueExW(hkey, name_w.as_ptr(), 0, value_type, data.as_ptr(), len) };

View on GitHub (pinned to 61d99ed8e1)