{"record":{"id":"e754781f74c00f8f","repo":"Hmbown/CodeWhale","slug":"cannot-export-a-root-model-alias-into-a-non-table-provider","errorCode":null,"errorMessage":"Cannot export a root model alias into a non-table provider slot","messagePattern":"Cannot export a root model alias into a non-table provider slot","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/route_preferences.rs","lineNumber":221,"sourceCode":"            scoped.default_text_model = Some(value.to_string());\n            let wire_model = crate::config::wire_model_for_provider_route(\n                identity.provider,\n                &scoped.active_route_base_url(),\n                &value,\n            );\n            if scoped.default_model() == wire_model {\n                document.remove(root_key);\n                continue;\n            }\n            if crate::config::normalize_model_name(&value).is_none() {\n                document.remove(root_key);\n                continue;\n            }\n            if document_slot_value(document, &deepseek_slot).is_some() {\n                document.remove(root_key);\n                continue;\n            }\n            ensure!(\n                insert_document_slot_value(document, &deepseek_slot, &value),\n                \"Cannot export a root model alias into a non-table provider slot\"\n            );\n            document.remove(root_key);\n        }\n    }\n\n    match document.get(\"default_model\").and_then(toml::Value::as_str) {\n        Some(value) => {\n            let value = value.trim().to_string();\n            // A root alias the DeepSeek route still consumes lands in this\n            // same slot on import; the live choice wins over the dead alias.\n            let root_covers_slot = active_slot == deepseek_slot\n                && [\"model\", \"default_text_model\"]\n                    .iter()\n                    .any(|key| document.get(*key).and_then(toml::Value::as_str).is_some());\n            let folded = !value.is_empty()\n                && !root_covers_slot","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/route_preferences.rs#L203-L239","documentation":"During export, scrub_root_model_aliases_for_export moves a root model alias's value into the canonical provider table slot (providers.<id>.model). insert_document_slot_value fails (returns false) when the target provider entry is not a TOML table, so the code refuses to proceed rather than silently dropping the alias value. This guards against data loss when the config shape is unexpected.","triggerScenarios":"Exporting a document where the root alias key (e.g. \"model\" or \"default_text_model\") has a value, the canonical provider slot is empty, but document[\"providers\"][slot_id] exists as a non-table value (e.g. a string), so the value cannot be inserted.","commonSituations":"Hand-edited or legacy config files where providers.<id> was written as a scalar instead of a table; migration from an older schema.","solutions":["Fix the config so providers.<id> is a proper TOML table containing a model field","Remove or correct the scalar value at the conflicting path before exporting","Re-run export after normalizing the document with the standard config editor"],"exampleFix":"# before (broken config)\nproviders.deepseek = \"something\"\n# after\n[providers.deepseek]\nmodel = \"deepseek-chat\"","handlingStrategy":"validation","validationCode":"fn slot_is_table(doc: &toml::Table, slot: &[String]) -> bool {\n    matches!(doc.get(slot[0]).and_then(|v| v.get(slot[1])), Some(toml::Value::Table(_)))\n}","typeGuard":null,"tryCatchPattern":"match scrub_root_model_aliases_for_export(&mut doc) {\n    Err(e) if e.to_string().contains(\"non-table provider slot\") => eprintln!(\"fix providers.<id> to be a TOML table: {e}\"),\n    Err(e) => return Err(e),\n    Ok(()) => {}\n}","preventionTips":["Never write scalar values under providers.<id>","Round-trip configs through the app's save path rather than hand-editing TOML","Validate config shape before export"],"tags":["config","toml","export"],"backgroundTag":"incompatible-source-type","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T06:17:15.046Z"}