{"record":{"id":"e0392d95b3089e79","repo":"Hmbown/CodeWhale","slug":"not-a-route-preference-key-key","errorCode":null,"errorMessage":"Not a route preference key: {key}","messagePattern":"Not a route preference key: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/route_preferences.rs","lineNumber":286,"sourceCode":"        original\n    } else {\n        rendered = store.rendered_body()?;\n        &rendered\n    };\n    let mut config = parse_config(body)?;\n    if config.route_preferences_version.is_none()\n        && crate::config::is_home_config_path(store.path())\n    {\n        config.apply_saved_selection(\n            &crate::settings::Settings::load_legacy_route_preferences_read_only()?,\n        );\n    }\n    Ok(config)\n}\n\n/// Read the saved route without applying launch overrides or credentials.\npub fn get(path: &Path, key: &str) -> Result<Option<String>> {\n    ensure!(is_route_key(key), \"Not a route preference key: {key}\");\n    let store = codewhale_config::ConfigStore::load(Some(path.to_path_buf()))?;\n    if let Some(key) = project_root_key(store.path(), key) {\n        return Ok(store.config.get_value(key));\n    }\n    let mut config = saved_config(&store)?;\n    if key == \"provider\" {\n        return Ok(Some(\n            config.provider.unwrap_or_else(|| \"deepseek\".to_string()),\n        ));\n    }\n    let identity = model_identity(&config, key)?;\n    config.scope_to_provider_identity(&identity);\n    Ok(config\n        .provider_config_for(identity.provider)\n        .and_then(|entry| entry.model.clone())\n        .or_else(|| {\n            (provider_model_id(key).is_none()\n                && (config.default_text_model.is_some() || config.legacy_model.is_some()))","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/route_preferences.rs#L268-L304","documentation":"get reads the saved route preference for a key without applying launch overrides or credentials. It first validates the key with is_route_key and rejects anything that is not a provider or model selection key. This keeps reads from silently returning data for unknown or device-specific keys.","triggerScenarios":"Calling route_preferences::get(path, key) with key not in {provider, model, default_model, default_text_model, providers.<id>.model}; e.g. typos like \"models\" or arbitrary config keys.","commonSituations":"Scripts querying route state with mistyped key names; callers assuming any config key is readable through this API.","solutions":["Use a valid route key: provider, model, default_model, default_text_model, or providers.<id>.model","Validate with is_route_key(key) before calling get","Correct the key spelling"],"exampleFix":"// before\nlet v = get(&path, \"model_provider\")?;\n// after\nlet v = get(&path, \"provider\")?;","handlingStrategy":"validation","validationCode":"if !is_route_key(key) { return Err(anyhow!(\"{key} is not a route preference key\")); }","typeGuard":"fn is_route_key(key: &str) -> bool {\n    matches!(key, \"provider\"|\"model\"|\"default_model\"|\"default_text_model\")\n        || key.strip_prefix(\"providers.\").and_then(|r| r.strip_suffix(\".model\")).is_some_and(|id| !id.is_empty())\n}","tryCatchPattern":"match get(&path, key) {\n    Ok(v) => v,\n    Err(e) if e.to_string().contains(\"Not a route preference key\") => { eprintln!(\"use provider|model|default_model|default_text_model|providers.<id>.model\"); None }\n    Err(e) => return Err(e),\n}","preventionTips":["Use is_route_key as a pre-check","Centralize route key names in constants","Avoid forwarding arbitrary config keys to route APIs"],"tags":["config","validation","api-misuse"],"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-23T08:17:48.524Z"}