{"record":{"id":"6a722420d4b8656b","repo":"jdx/mise","slug":"expected-dictionary-along-defaults-patch-path-request","errorCode":null,"errorMessage":"expected dictionary along defaults patch path: {request}","messagePattern":"expected dictionary along defaults patch path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/defaults.rs","lineNumber":331,"sourceCode":"            eyre::ensure!(\n                !overlaps,\n                \"overlapping macOS defaults declarations: {other}; {request}\"\n            );\n        }\n    }\n    Ok(())\n}\n\nfn selected_value<'a>(\n    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) {","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/defaults.rs#L313-L349","documentation":"When evaluating a macOS `defaults` patch, the code walks a plist path expecting every intermediate node to be a dictionary. If a component along the path resolves to a non-dictionary value (array, string, date, etc.), it cannot descend further and this error is raised, naming the full request.","triggerScenarios":"A defaults patch whose `path` traverses a key that exists but holds a scalar or array instead of a nested dictionary — e.g. path [\"a\",\"b\"] where plist['a'] is a string.","commonSituations":"Domain plist shape changed between macOS versions, user hand-edited the plist, or the patch path was written against a different schema than the actual domain.","solutions":["Inspect the actual plist (`defaults read <domain>`) and correct the path to only traverse dictionaries","Delete/reset the offending key so patch_value can create a dictionary at that position","Update the patch configuration to match the current plist structure"],"exampleFix":"// before: path = [\"Window\", \"Frame\"] where 'Window' is a string\n// after: path = [\"NSWindow Frame\"][\"Main\"] — fix path or reset key:\n// defaults delete MyApp Window","handlingStrategy":"type-guard","validationCode":"fn path_is_dict_traversable(root: &plist::Value, path: &[String]) -> bool {\n    let mut cur = Some(root);\n    for key in path {\n        match cur {\n            Some(plist::Value::Dictionary(d)) => cur = d.get(key),\n            _ => return false,\n        }\n    }\n    true\n}","typeGuard":"fn as_dictionary(v: Option<&plist::Value>) -> Option<&plist::Dictionary> {\n    match v { Some(plist::Value::Dictionary(d)) => Some(d), _ => None }\n}","tryCatchPattern":"match selected_value(&request) {\n    Err(e) if e.to_string().starts_with(\"expected dictionary along defaults patch path\") => {\n        eprintln!(\"plist shape mismatch for {}: reading live defaults\", request);\n    }\n    r => r?,\n}","preventionTips":["Read the live domain with `defaults read` and shape the path against reality","Only traverse keys known to hold dictionaries","Re-validate paths after macOS version upgrades"],"tags":["macos","plist","defaults","path"],"backgroundTag":"type-mismatch","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"}