{"record":{"id":"635fc0f9722ea64c","repo":"ramensoftware/windhawk","slug":"value-name-name-why","errorCode":null,"errorMessage":"value name {name:?} {why}","messagePattern":"value name (.+?) (.+?)","errorType":"validation","errorClass":"SettingsError","httpStatus":null,"severity":"error","filePath":"src/windhawk-core/windows/src/ini.rs","lineNumber":179,"sourceCode":"    /// one answer whichever operation carries it, in both storage modes.\n    fn check_name(&self, op: &'static str, name: &str) -> Result<(), SettingsError> {\n        if name.contains('\\0') {\n            return Err(self.err(op, 0, &format!(\"value name {name:?} contains a NUL\")));\n        }\n        Ok(())\n    }\n}\n\nimpl SettingsTree for IniTree {\n    fn get_string(&self, name: &str) -> Result<Option<String>, SettingsError> {\n        self.check_name(\"get\", name)?;\n        get_profile_string(&self.file, &self.section, name)\n            .map_err(|os| self.err(\"get\", os, \"GetPrivateProfileString\"))\n    }\n\n    fn set_string(&mut self, name: &str, value: &str) -> Result<(), SettingsError> {\n        if let Some(why) = unrepresentable_name(name) {\n            return Err(self.err(\"set\", 0, &format!(\"value name {name:?} {why}\")));\n        }\n        // `WritePrivateProfileStringW` takes the value as a NUL-terminated\n        // string, so an embedded NUL ends it: everything after it is dropped and\n        // the call still reports success. `escape_ini_value` cannot rescue that\n        // (the INI line format has no encoding for a NUL), so refuse the write\n        // rather than store a silently truncated value.\n        if value.contains('\\0') {\n            return Err(self.err(\"set\", 0, \"value contains a NUL character\"));\n        }\n        // An INI entry ends at the line break, so a value carrying one cannot\n        // be stored either: it would read back cut at the break, with the rest\n        // of it parsed as further lines of a file that also holds the mod's\n        // `[Mod]` config. Refused for the same reason as a NUL - the registry\n        // backend stores both halves of such a value faithfully, and a write\n        // that cannot keep the value is better refused than reported as done.\n        if value.contains(['\\r', '\\n']) {\n            return Err(self.err(\"set\", 0, \"value contains a line break\"));\n        }","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk-core/windows/src/ini.rs#L161-L197","documentation":"IniTree::set_string first validates the value name with unrepresentable_name and refuses names that cannot be faithfully represented in the INI backend (message: \"value name {name:?} {why}\"). This exists because Win32 INI APIs and the registry backend would otherwise treat such names differently, so the write is rejected up front for consistency.","triggerScenarios":"Calling set_string — also reached via set_int and set_binary — with a name that unrepresentable_name rejects (e.g. a name containing NUL or otherwise unrepresentable in the INI line format).","commonSituations":"Names built from raw buffers containing terminators; programmatic key generation embedding invalid characters; migrating registry-stored settings with names that only the registry can represent.","solutions":["Check the unrepresentable_name rejection reason in the error and sanitize the name accordingly (strip NUL/invalid characters).","Validate names before writing: only allow names you would accept on read too.","Use the registry backend for names that genuinely cannot live in an INI line.","Surface the error to the caller instead of silently writing a truncated name."],"exampleFix":"// before\nsettings.set_string(user_supplied_key, \"1\")?;\n\n// after\nlet key = user_supplied_key.split('\\0').next().unwrap_or_default();\nif !key.is_empty() {\n    settings.set_string(key, \"1\")?;\n}","handlingStrategy":"validation","validationCode":"fn writable_name(name: &str) -> Result<&str, String> {\n    if name.contains('\\0') { Err(format!(\"name {name:?} contains NUL\")) }\n    else if name.is_empty() { Err(\"name is empty\".into()) }\n    else { Ok(name) }\n}","typeGuard":"fn writable_name(name: &str) -> Option<&str> {\n    (!name.contains('\\0') && !name.is_empty()).then_some(name)\n}","tryCatchPattern":"if let Err(e) = ini.set_string(&key, &value) {\n    if e.to_string().contains(\"value name\") {\n        let key = sanitize(&key);\n        ini.set_string(&key, &value)?;\n    } else { return Err(e.into()); }\n}","preventionTips":["Sanitize setting names once at the configuration boundary, not at each call site.","Restrict generated key names to a safe charset (alphanumeric, dot, dash, underscore).","Test write/read round-trips with the same names to catch backend mismatches early.","Do not persist raw interop strings as setting names."],"tags":["ini","validation","nul-character","windows","write-path"],"backgroundTag":"invalid-argument-value","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"}