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

agents.{agent_alias}.model_provider resolves to a model_prov

Error message

agents.{agent_alias}.model_provider resolves to a model_provider entry with no `model` set. Configure [providers.models.{provider_name}.<alias>] model = "...".

What it means

The agent's model_provider reference resolved to a real [providers.models.<type>.<alias>] entry, but that entry's model field is unset, empty, or whitespace-only (the value is trimmed and filtered before the check). ZeroClaw refuses to construct the agent with an indeterminate model — the message names the exact table to fix.

Source

Thrown at crates/zeroclaw-runtime/src/agent/agent.rs:1714

            reaction_handle,
            poll_handle,
            escalate_handle,
            channel_room_handle,
            activated_handle,
            // from_config performs no per-turn tool_filter_groups filtering
            // itself, so mcp_tool_names is dropped here along with `registry`'s
            // already-consumed sibling fields via `..`.
            ..
        } = assembled;
        let tools = registry.into_inner();

        let model_name = match agent_model_provider
            .and_then(|e| e.model.as_deref())
            .map(str::trim)
            .filter(|m| !m.is_empty())
        {
            Some(m) => m.to_string(),
            None => anyhow::bail!(
                "agents.{agent_alias}.model_provider resolves to a model_provider entry \
                 with no `model` set. Configure [providers.models.{provider_name}.<alias>] \
                 model = \"...\".",
            ),
        };

        let provider_ref = format!("{provider_name}.{provider_alias}");
        let provider_runtime_options = zeroclaw_providers::provider_runtime_options_for_alias(
            config,
            provider_name,
            provider_alias,
        );

        let model_provider: Box<dyn ModelProvider> =
            zeroclaw_providers::create_routed_model_provider_with_options(
                config,
                &provider_ref,
                agent_model_provider.and_then(|e| e.api_key.as_deref()),

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Add model = "<model-id>" under the named [providers.models.<type>.<alias>] table.
  2. Remove surrounding whitespace from the model value — blank-after-trim is treated as unset.
  3. Validate every resolved provider entry has a non-empty model at startup.

Example fix

# before
[providers.models.anthropic.default]
# model key missing / left empty
model = ""

# after
[providers.models.anthropic.default]
model = "claude-sonnet-4-5"
Defensive patterns

Strategy: validation

Validate before calling

// Startup lint: resolved entries must carry a model
for alias in config.agents.keys() {
    if let Some((_p, _a, entry)) = config.resolved_model_provider_for_agent(alias) {
        anyhow::ensure!(
            entry.model.as_deref().map(str::trim).filter(|m| !m.is_empty()).is_some(),
            "provider entry for {alias} has no model"
        );
    }
}

Prevention

When it happens

Trigger: A provider table created with api credentials but no model key; model = "" or model = " " surviving a trim; a table stubbed out during setup and never completed.

Common situations: Provisioning provider auth first and intending to set the model later; copy-paste of a provider template that omits model; commented-out model line that was actually deleted.

Related errors


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