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

model_provider reference must not be empty

Error message

model_provider reference must not be empty

What it means

Thrown by model_provider_entry_for_ref when the model_provider string is empty (or only whitespace) after trimming. This is the low-level guard behind dotted-ref resolution: before any `<type>.<alias>` split is attempted, the reference must be non-empty. Callers reach it from resolved_runtime_model_provider_ref and any other code resolving a raw provider reference against `config.providers.models`.

Source

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

        .get(agent_alias)
        .with_context(|| format!("agents.{agent_alias} is not configured"))?;
    let configured = agent.model_provider.trim();
    if configured.is_empty() {
        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> {

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Find the caller that produced the empty reference and fix the source value (agent config field, CLI arg, or API payload)
  2. If the reference is optional in your flow, check emptiness before calling the resolver instead of relying on the error
  3. Set a valid dotted ref such as `openai.default` at the origin

Example fix

// before
let (r, entry) = model_provider_entry_for_ref(&config, agent.model_provider.as_str())?;

// after
let provider_ref = agent.model_provider.trim();
if provider_ref.is_empty() {
    anyhow::bail!("agent `{alias}` has no model_provider configured");
}
let (r, entry) = model_provider_entry_for_ref(&config, provider_ref)?;
Defensive patterns

Strategy: validation

Validate before calling

let provider_ref = model_provider.trim();
if provider_ref.is_empty() {
    anyhow::bail!("model_provider reference is empty at source `{source}`");
}
let (ref_, entry) = model_provider_entry_for_ref(config, provider_ref)?;

Try / catch

Err(err) if err.to_string() == "model_provider reference must not be empty" => {
    // reject the payload/request that carried the empty reference
}

Prevention

When it happens

Trigger: Calling model_provider_entry_for_ref(config, "") or with a whitespace-only string; typically the downstream result of an agents entry, CLI argument, or gateway payload that carried an empty provider reference.

Common situations: Upstream code reads an optional field with `.unwrap_or_default()` and passes the empty string along; gateway/JSON payload where model_provider was omitted but the field type forced ""; whitespace-only value pasted into config.

Related errors


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