{"record":{"id":"a8a718ed3749858f","repo":"jdx/mise","slug":"defaults-patch-path-must-not-be-empty","errorCode":null,"errorMessage":"defaults patch path must not be empty","messagePattern":"defaults patch path must not be empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/defaults.rs","lineNumber":341,"sourceCode":"    mut current: Option<&'a plist::Value>,\n    request: &DefaultsRequest,\n) -> Result<Option<&'a plist::Value>> {\n    if let Some(path) = &request.path {\n        for component in path {\n            current = match current {\n                Some(plist::Value::Dictionary(dict)) => dict.get(component),\n                None => return Ok(None),\n                Some(_) => eyre::bail!(\"expected dictionary along defaults patch path: {request}\"),\n            };\n        }\n    }\n    Ok(current)\n}\n\n#[cfg(any(target_os = \"macos\", test))]\nfn patch_value(current: &mut plist::Value, path: &[String], value: plist::Value) -> Result<()> {\n    let Some((key, rest)) = path.split_first() else {\n        eyre::bail!(\"defaults patch path must not be empty\");\n    };\n    let dict = current\n        .as_dictionary_mut()\n        .ok_or_else(|| eyre::eyre!(\"expected dictionary along defaults patch path\"))?;\n    if rest.is_empty() {\n        dict.insert(key.clone(), value);\n    } else {\n        if !dict.contains_key(key) {\n            dict.insert(\n                key.clone(),\n                plist::Value::Dictionary(plist::Dictionary::new()),\n            );\n        }\n        patch_value(\n            dict.get_mut(key).expect(\"dictionary entry inserted\"),\n            rest,\n            value,\n        )?;","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/defaults.rs#L323-L359","documentation":"`patch_value` requires at least one path component because it must know which dictionary key to insert. It also assumes the current node is a dictionary; an empty path (or a non-dictionary current node, which yields the sibling 'expected dictionary' error) cannot be patched.","triggerScenarios":"Calling patch_value with an empty path slice — e.g. a patch request with no key components — typically when the final path segment was consumed by recursion or the config omitted a key.","commonSituations":"Malformed defaults patch definitions missing the final key, or recursive patching logic splitting the path down to zero components.","solutions":["Provide a non-empty path ending in the key to set (e.g. [\"key\"])","Fix the patch configuration so the final key name is present","Check the recursion/caller logic so the last component is not stripped before patch_value"],"exampleFix":"// before\npatch_value(&mut root, &[], value)?; // empty path\n// after\npatch_value(&mut root, &[\"SomeKey\".to_string()], value)?;","handlingStrategy":"validation","validationCode":"if path.is_empty() {\n    return Err(\"defaults patch path must not be empty\".into());\n}","typeGuard":null,"tryCatchPattern":"match patch_value(&mut root, &path, value) {\n    Err(e) if e.to_string().contains(\"path must not be empty\") => eprintln!(\"patch request missing key path\"),\n    r => r?,\n}","preventionTips":["Require an explicit final key in every defaults patch definition","Validate patch requests (non-empty path) at config load time","Unit-test patch helpers with edge cases including empty paths"],"tags":["macos","plist","defaults","empty-path"],"backgroundTag":"empty-required-field","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}