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

agents.{agent_alias}.model_provider is empty; runtime reload

Error message

agents.{agent_alias}.model_provider is empty; runtime reload requires a dotted `<type>.<alias>` provider reference

What it means

Thrown by resolved_runtime_model_provider_ref when a runtime model reload looks up `config.agents.get(agent_alias)` and finds the agent's `model_provider` field empty after trimming. Runtime reloads need a fully-qualified dotted `<type>.<alias>` reference (e.g. `openai.fast`) to know exactly which credentialed provider entry to rebuild the client from; an empty string cannot be resolved, so the reload aborts rather than guessing a default.

Source

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

            )
        }
        ModelsCommandResolution::Unknown => {
            anyhow::bail!("unknown model_provider `{raw}`")
        }
    }
}

fn resolved_runtime_model_provider_ref(
    config: &Config,
    agent_alias: &str,
) -> anyhow::Result<String> {
    let agent = config
        .agents
        .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");

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Set an explicit dotted provider ref on the agent: `zeroclaw config set agents.<agent_alias>.model_provider "openai.default"`
  2. Verify the `<type>.<alias>` pair actually exists under `[providers.models]` before saving
  3. Restart or re-trigger the runtime reload; the agent now resolves to a concrete provider entry

Example fix

# before (zeroclaw.toml)
[agents.main]
model = "gpt-4o"
# no model_provider -> reload fails

# after
[agents.main]
model = "gpt-4o"
model_provider = "openai.default"
Defensive patterns

Strategy: validation

Validate before calling

let provider_ref = config
    .agents
    .get(agent_alias)
    .map(|a| a.model_provider.trim().to_string())
    .filter(|p| !p.is_empty())
    .with_context(|| format!("agent `{agent_alias}` needs agents.{agent_alias}.model_provider set"))?;

Try / catch

Err(err) if err.to_string().contains("model_provider is empty") => {
    // prompt operator to set agents.<alias>.model_provider before retrying reload
}

Prevention

When it happens

Trigger: Triggering a runtime model reload for an agent whose `[agents.<alias>]` section exists but has no `model_provider` key (or it is set to "" or whitespace). This happens via the orchestrator's reload path that calls resolved_runtime_model_provider_ref(config, agent_alias).

Common situations: Agent stanza copied from a template that omitted `model_provider`; the field was commented out or blanked during config cleanup; relying on a global default provider and assuming per-agent reload works without an explicit per-agent reference.

Related errors


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