{"record":{"id":"44a16b690a9f6cea","repo":"Hmbown/CodeWhale","slug":"not-a-model-preference-key-key","errorCode":null,"errorMessage":"Not a model preference key: {key}","messagePattern":"Not a model preference key: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/route_preferences.rs","lineNumber":88,"sourceCode":"        return Ok(vec![\"default_text_model\"]);\n    }\n    let key = match identity.provider {\n        ApiProvider::Custom => identity.key.as_str(),\n        ApiProvider::DeepseekCN => \"deepseek_cn\",\n        ApiProvider::OllamaCloud if identity.migrated_legacy_ollama_cloud_route => \"ollama\",\n        provider => provider\n            .metadata()\n            .context(\"provider model table\")?\n            .provider_config_key(),\n    };\n    Ok(vec![\"providers\", key, \"model\"])\n}\n\n/// Locate the canonical model leaf in a saved document without applying\n/// device preferences or launch overrides. Export uses this same identity\n/// resolution to omit only root aliases shadowed by that leaf.\npub fn model_slot_for_document(body: &str, key: &str) -> Result<Vec<String>> {\n    ensure!(\n        is_route_key(key) && key != \"provider\",\n        \"Not a model preference key: {key}\"\n    );\n    let config = parse_config(body)?;\n    let identity = model_identity(&config, key)?;\n    Ok(model_slot(&identity)?\n        .into_iter()\n        .map(str::to_string)\n        .collect())\n}\n\nfn document_slot_value(document: &toml::value::Table, slot: &[String]) -> Option<String> {\n    let [root, provider, field] = slot else {\n        return None;\n    };\n    document\n        .get(root)?\n        .as_table()?","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/route_preferences.rs#L70-L106","documentation":"model_slot_for_document resolves which TOML slot (e.g. providers.<id>.model or default_text_model) a saved model preference lives in, for export. It rejects any key that is not a recognized route/model preference key (per is_route_key) or the 'provider' key, because 'provider' does not name a model slot. This is input validation to prevent writing/reading model data under an unknown config path.","triggerScenarios":"Calling model_slot_for_document(body, key) with key outside {model, default_model, default_text_model, providers.<id>.model} or with key == \"provider\"; e.g. passing \"provider\", a typo like \"defaultmodel\", or a device-preference key.","commonSituations":"Export/migration tooling iterating saved Settings keys; key spelling drift after renames; scripts forwarding arbitrary config keys without filtering to model keys.","solutions":["Pass only keys accepted by is_route_key and not equal to \"provider\"","Filter the key list through the same is_route_key predicate before calling","Check the key spelling against the documented route keys (model, default_model, default_text_model, providers.<id>.model)"],"exampleFix":"// before\nlet slot = model_slot_for_document(&body, \"provider\")?;\n// after\nif is_route_key(key) && key != \"provider\" {\n    let slot = model_slot_for_document(&body, key)?;\n}","handlingStrategy":"validation","validationCode":"if !is_route_key(key) || key == \"provider\" { return Err(anyhow!(\"skip: {key} is not a model preference key\")); }","typeGuard":"fn is_model_pref_key(key: &str) -> bool { is_route_key(key) && key != \"provider\" }","tryCatchPattern":null,"preventionTips":["Filter key lists through is_route_key before any route_preferences API","Exclude \"provider\" when working with model slots","Keep key names in a shared constant list instead of string literals"],"tags":["config","validation","toml"],"backgroundTag":"invalid-config-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T10:30:35.592Z"}