Hmbown/CodeWhale · error
Cannot export a root model alias into a non-table provider…
Error message
Cannot export a root model alias into a non-table provider slot
What it means
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.
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
Example fix
# before (broken config) providers.deepseek = "something" # after [providers.deepseek] model = "deepseek-chat"
Defensive patterns
Strategy: validation
Validate before calling
fn slot_is_table(doc: &toml::Table, slot: &[String]) -> bool {
matches!(doc.get(slot[0]).and_then(|v| v.get(slot[1])), Some(toml::Value::Table(_)))
} Try / catch
match scrub_root_model_aliases_for_export(&mut doc) {
Err(e) if e.to_string().contains("non-table provider slot") => eprintln!("fix providers.<id> to be a TOML table: {e}"),
Err(e) => return Err(e),
Ok(()) => {}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Hand-edited or legacy config files where providers.<id> was written as a scalar instead of a table; migration from an older schema.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Cannot export default_model into a non-table provider slot
- active profile is missing or malformed
- Cannot export a non-string default_model without losing its…
- config entry must be a string
- config export requires --portable; plain export is not…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/e754781f74c00f8f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/route_preferences.rs:221
scoped.default_text_model = Some(value.to_string());
let wire_model = crate::config::wire_model_for_provider_route(
identity.provider,
&scoped.active_route_base_url(),
&value,
);
if scoped.default_model() == wire_model {
document.remove(root_key);
continue;
}
if crate::config::normalize_model_name(&value).is_none() {
document.remove(root_key);
continue;
}
if document_slot_value(document, &deepseek_slot).is_some() {
document.remove(root_key);
continue;
}
ensure!(
insert_document_slot_value(document, &deepseek_slot, &value),
"Cannot export a root model alias into a non-table provider slot"
);
document.remove(root_key);
}
}
match document.get("default_model").and_then(toml::Value::as_str) {
Some(value) => {
let value = value.trim().to_string();
// A root alias the DeepSeek route still consumes lands in this
// same slot on import; the live choice wins over the dead alias.
let root_covers_slot = active_slot == deepseek_slot
&& ["model", "default_text_model"]
.iter()
.any(|key| document.get(*key).and_then(toml::Value::as_str).is_some());
let folded = !value.is_empty()
&& !root_covers_slotView on GitHub (pinned to 73e0f67d83)