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

  1. Fix the config so providers.<id> is a proper TOML table containing a model field
  2. Remove or correct the scalar value at the conflicting path before exporting
  3. 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

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


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_slot

View on GitHub (pinned to 73e0f67d83)