zeroclaw-labs/zeroclaw · error

providers.models.ollama.{alias}.model uses ':cloud', but no

Error message

providers.models.ollama.{alias}.model uses ':cloud', but no API key is configured. Set api_key on [providers.models.ollama.{alias}] (or via the schema-mirror grammar: ZEROCLAW_providers__models__ollama__{alias}__api_key=<value>).

What it means

When a ':cloud' model's uri host is exactly ollama.com or api.ollama.com (is_official_ollama_cloud_endpoint, schema.rs:19374) and the entry's api_key is None or whitespace-only (has_ollama_cloud_credential, schema.rs:19390), validation fails. The message names both the TOML fix and the schema-mirror env grammar ZEROCLAW_providers__models__ollama__{alias}__api_key as alternative injection points. Keys configured on other aliases do not count.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:21678

        for (alias, cfg) in &self.providers.models.ollama {
            let entry = &cfg.base;
            if !entry
                .model
                .as_deref()
                .is_some_and(|model| model.trim().ends_with(":cloud"))
            {
                continue;
            }

            if is_local_ollama_endpoint(entry.uri.as_deref()) {
                anyhow::bail!(
                    "providers.models.ollama.{alias}.model uses ':cloud', but uri is local or unset. Set uri to a remote Ollama endpoint (for example https://ollama.com)."
                );
            }
            if is_official_ollama_cloud_endpoint(entry.uri.as_deref())
                && !has_ollama_cloud_credential(entry.api_key.as_deref())
            {
                anyhow::bail!(
                    "providers.models.ollama.{alias}.model uses ':cloud', but no API key is configured. Set api_key on [providers.models.ollama.{alias}] (or via the schema-mirror grammar: ZEROCLAW_providers__models__ollama__{alias}__api_key=<value>)."
                );
            }
        }

        // Microsoft 365
        if self.microsoft365.enabled {
            let tenant = self
                .microsoft365
                .tenant_id
                .as_deref()
                .map(str::trim)
                .filter(|s| !s.is_empty());
            if tenant.is_none() {
                anyhow::bail!(
                    "microsoft365.tenant_id must not be empty when microsoft365 is enabled"
                );
            }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Set api_key directly on the failing alias: `api_key = "..."` under [providers.models.ollama.<alias>]
  2. Or export ZEROCLAW_providers__models__ollama__<alias>__api_key=<value> in the process environment (alias spelled verbatim, double underscores between path segments)
  3. Verify the value is non-empty after trimming — whitespace-only still fails
  4. Confirm the alias in the message matches where you put the key

Example fix

# before
[providers.models.ollama.default]
model = "gpt-oss:cloud"
uri = "https://ollama.com"

# after
[providers.models.ollama.default]
model = "gpt-oss:cloud"
uri = "https://ollama.com"
api_key = "<ollama-cloud-key>"

# or, keep the file clean and export:
# ZEROCLAW_providers__models__ollama__default__api_key=<ollama-cloud-key>
Defensive patterns

Strategy: try-catch

Validate before calling

fn ollama_key_precheck(cfg: &zeroclaw_config::Config) -> Result<(), String> {
    for (alias, entry) in &cfg.providers.models.ollama {
        let cloud = entry.base.model.as_deref().is_some_and(|m| m.trim().ends_with(":cloud"));
        let official = entry.base.uri.as_deref().is_some_and(|u| {
            reqwest::Url::parse(u.trim()).ok()
                .and_then(|p| p.host_str().map(|h| h.eq_ignore_ascii_case("ollama.com") || h.eq_ignore_ascii_case("api.ollama.com")))
                .unwrap_or(false)
        });
        if cloud && official && entry.base.api_key.as_deref().map(str::trim).is_none_or(str::is_empty) {
            return Err(format!("alias {alias}: :cloud on official endpoint without api_key"));
        }
    }
    Ok(())
}

Type guard

fn cloud_entry_has_credential(api_key: Option<&str>) -> bool {
    api_key.map(str::trim).is_some_and(|v| !v.is_empty)
}

Try / catch

if let Err(err) = config.validate() {
    if err.to_string().contains("no API key is configured") {
        // export ZEROCLAW_providers__models__ollama__<alias>__api_key or set api_key in TOML, then reload
    }
}

Prevention

When it happens

Trigger: Configure `uri = "https://ollama.com"` with a ':cloud' model but api_key omitted, set to "", or whitespace-only; or provide the key via env var under a differently-spelled alias path.

Common situations: Keeping secrets out of the committed config but forgetting to export the env var in the deployment unit (systemd, container, CI shell); rotating keys and leaving the old alias empty; typos in the double-underscore env mirror path.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


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