zeroclaw-labs/zeroclaw · error · anyhow::Error

model_provider `{trimmed}` must use `<type>.<alias>` form

Error message

model_provider `{trimmed}` must use `<type>.<alias>` form

What it means

Thrown by model_provider_entry_for_ref when the trimmed provider reference contains no '.' separator, so `split_once('.')` fails. ZeroClaw model providers are addressed as `<type>.<alias>` (e.g. `openai.default`) because each family can hold multiple credentialed aliases under `[providers.models.<type>.<alias>]`; a bare name like `openai` is ambiguous at this layer and is rejected before lookup.

Source

Thrown at crates/zeroclaw-channels/src/orchestrator/mod.rs:1626

        anyhow::bail!(
            "agents.{agent_alias}.model_provider is empty; runtime reload requires a dotted `<type>.<alias>` provider reference"
        );
    }
    let (model_provider, _) = model_provider_entry_for_ref(config, configured)?;
    Ok(model_provider)
}

fn model_provider_entry_for_ref<'a>(
    config: &'a Config,
    model_provider: &str,
) -> anyhow::Result<(String, &'a zeroclaw_config::schema::ModelProviderConfig)> {
    let trimmed = model_provider.trim();
    if trimmed.is_empty() {
        anyhow::bail!("model_provider reference must not be empty");
    }

    let Some((provider_type, provider_alias)) = trimmed.split_once('.') else {
        anyhow::bail!("model_provider `{trimmed}` must use `<type>.<alias>` form");
    };
    let Some(entry) = config.providers.models.find(provider_type, provider_alias) else {
        anyhow::bail!("model_provider `{trimmed}` does not resolve to a configured provider");
    };
    Ok((trimmed.to_string(), entry))
}

/// Resolve runtime defaults from `config` against a specific dotted
/// `model_provider` reference (`"<type>.<alias>"`) — the per-agent
/// resolution path.
fn runtime_defaults_from_config(
    config: &Config,
    model_provider: &str,
) -> anyhow::Result<ChannelRuntimeDefaults> {
    let (default_model_provider, entry) = model_provider_entry_for_ref(config, model_provider)?;
    let model = entry
        .model
        .as_deref()

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Change the reference to dotted form: `openai` -> `openai.default` (using an alias that exists in config)
  2. Confirm the alias under `[providers.models.<type>]` in zeroclaw.toml and match it exactly after the dot
  3. For `/models` chat commands the bare family form is fine — only config fields and programmatic refs require the dot

Example fix

# before
[agents.main]
model_provider = "openai"
# error: model_provider `openai` must use `<type>.<alias>` form

# after
[agents.main]
model_provider = "openai.default"
Defensive patterns

Strategy: validation

Validate before calling

fn is_dotted_provider_ref(s: &str) -> bool {
    let t = s.trim();
    !t.is_empty() && t.split_once('.').is_some_and(|(a, b)| !a.is_empty() && !b.is_empty())
}
assert!(is_dotted_provider_ref(&agent.model_provider), "must be `<type>.<alias>`");

Type guard

fn is_dotted_provider_ref(s: &str) -> bool {
    let t = s.trim();
    !t.is_empty()
        && t.split_once('.')
            .is_some_and(|(ty, alias)| !ty.is_empty() && !alias.is_empty() && !alias.contains('.'))
}

Try / catch

Err(err) if err.to_string().contains("must use `<type>.<alias>` form") => {
    // rewrite bare family names to `<family>.default` when that alias exists, else reject
}

Prevention

When it happens

Trigger: Calling model_provider_entry_for_ref (or the runtime reload path that wraps it) with values like `openai`, `anthropic`, or `my provider` — anything without a dot. Note the `/models` chat command tolerates bare family names via resolve_models_command; this stricter dotted-only contract applies to config-file references and programmatic callers.

Common situations: Writing `model_provider = "openai"` in an agent stanza copied from older docs or another tool's style; assuming a default alias is implied; using a colon or slash separator instead of a dot.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/e82cf17b2d148619. Report an issue: GitHub.