{"record":{"id":"f1173305e1777d30","repo":"ramensoftware/windhawk","slug":"set-on-a-read-only-absent-key","errorCode":null,"errorMessage":"set on a read-only/absent key","messagePattern":"set on a read-only/absent key","errorType":"validation","errorClass":"SettingsError","httpStatus":null,"severity":"error","filePath":"src/windhawk-core/windows/src/registry.rs","lineNumber":453,"sourceCode":"                &mut value_type,\n                buf.as_mut_ptr(),\n                &mut data_size,\n            )\n        };\n        if rc == ERROR_FILE_NOT_FOUND {\n            return Ok(None);\n        }\n        if rc != ERROR_SUCCESS {\n            return Err(self.err(\"get\", rc, \"RegQueryValueEx (data)\"));\n        }\n        buf.truncate(data_size as usize);\n        Ok(Some((value_type, buf)))\n    }\n\n    fn set_raw(&self, name: &str, value_type: u32, data: &[u8]) -> Result<(), SettingsError> {\n        self.check_name(\"set\", name)?;\n        let Some(hkey) = self.hkey() else {\n            return Err(self.err(\"set\", 0, \"set on a read-only/absent key\"));\n        };\n        let name_w = to_wide(name);\n        // A length the API's u32 cannot hold has no honest value to pass, and a\n        // clamped one would hand the call a length the buffer does not have.\n        let len = u32::try_from(data.len())\n            .map_err(|_| self.err(\"set\", 0, \"value is too large for the registry\"))?;\n        // SAFETY: name_w is NUL-terminated; data/len describe a valid buffer.\n        let rc =\n            unsafe { RegSetValueExW(hkey, name_w.as_ptr(), 0, value_type, data.as_ptr(), len) };\n        if rc == ERROR_SUCCESS {\n            Ok(())\n        } else {\n            Err(self.err(\"set\", rc, \"RegSetValueEx\"))\n        }\n    }\n}\n\n/// Decode a `REG_SZ` byte buffer (UTF-16LE, possibly NUL-terminated).","sourceCodeStart":435,"sourceCodeEnd":471,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk-core/windows/src/registry.rs#L435-L471","documentation":"set_raw was called but the object has no writable key handle — the registry tree was opened read-only or the key does not exist and could not be opened for write. The write cannot proceed, so it is refused with this message instead of attempting a doomed API call.","triggerScenarios":"Calling set_string/set_int/set_binary (via set_raw) on a settings object opened in read-only mode, or when the backing registry key is absent and no write handle could be acquired.","commonSituations":"Reading a mod's settings from a viewer/tool that opens keys read-only, then trying to save changes; key removed by an uninstaller while the settings object is open; opening a wrong hive/path that does not exist.","solutions":["Open the settings/tree in read-write mode before mutating values.","Create/open the registry key with KEY_SET_VALUE (or recreate it) before writing.","Check existence/writability first: if the key is gone, re-create it via the library's key-opening API.","Avoid mutating settings objects that were constructed for read-only inspection."],"exampleFix":"// before\nlet s = Settings::open_read_only(path)?;\ns.set_int(\"n\", 1)?; // Err: set on a read-only/absent key\n// after\nlet mut s = Settings::open_read_write(path)?; // writable handle\ns.set_int(\"n\", 1)?;","handlingStrategy":"validation","validationCode":"// check writability before mutating\nif !settings.is_writable() { return Err(\"settings opened read-only\".into()); }","typeGuard":null,"tryCatchPattern":"match settings.set_int(\"n\", 1) {\n    Err(e) if e.message().contains(\"read-only/absent\") => {\n        let mut w = Settings::open_read_write(path)?;\n        w.set_int(\"n\", 1)?;\n    }\n    r => r?,\n}","preventionTips":["Open settings read-write whenever you plan to mutate.","Track read-only vs read-write objects in types (separate handles) to catch misuse at compile time.","Verify the backing key exists before writes; recreate missing keys.","Do not share read-only views into code paths that save changes."],"tags":["registry","read-only","permissions","state"],"backgroundTag":"permission-denied","analyzedSha":"61d99ed8e182e1af1b60109612b6763ad1b4b74e","analyzedAt":"2026-09-12T14:02:41.115Z","contentChangedAt":"2026-09-12T14:02:41.115Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}