zeroclaw-labs/zeroclaw · error

providers.models.{profile_name}.uri must use http/https

Error message

providers.models.{profile_name}.uri must use http/https

What it means

When a model profile under [providers.models] declares a non-empty uri, it must parse as a URL (via reqwest::Url::parse) and its scheme must be exactly http or https. A URL that fails to parse produces the earlier 'is not a valid URL' error; a parsable URL with any other scheme (file, unix, ws, ftp, or a mistyped scheme) reaches this bail. Schemeless strings like `localhost:11434` parse with scheme "localhost" and fail here too.

Source

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

            let has_model = profile
                .model
                .as_deref()
                .is_some_and(|v| !v.trim().is_empty());
            if !has_uri && !has_api_key && !has_model {
                ::zeroclaw_log::record!(WARN, ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note).with_outcome(::zeroclaw_log::EventOutcome::Unknown).with_attrs(::serde_json::json!({"model_provider": profile_name, "profile_name": profile_name})), "providers.models. is empty (no uri / api_key / model). \
                     Skipping at runtime; run `zeroclaw quickstart` (or use the dashboard) \
                     to make this model_provider usable.");
                continue;
            }

            if let Some(uri) = profile.uri.as_deref().map(str::trim)
                && !uri.is_empty()
            {
                let parsed = reqwest::Url::parse(uri).with_context(|| {
                    format!("providers.models.{profile_name}.uri is not a valid URL")
                })?;
                if !matches!(parsed.scheme(), "http" | "https") {
                    anyhow::bail!("providers.models.{profile_name}.uri must use http/https");
                }
            }

            if let Some(temp) = profile.temperature {
                validate_temperature(temp).map_err(|e| {
                    ::zeroclaw_log::record!(
                        WARN,
                        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
                            .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                            .with_attrs(::serde_json::json!({
                                "profile": profile_name,
                                "temperature": temp,
                                "error": format!("{}", e),
                            })),
                        "providers.models.<alias>.temperature rejected"
                    );
                    anyhow::Error::msg(format!("providers.models.{profile_name}.temperature: {e}"))
                })?;

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Write an explicit http(s) URL — local daemons become `uri = "http://localhost:11434"`
  2. Move file- or socket-backed models to whichever provider surface supports them; providers.models is HTTP-only
  3. Fix scheme typos (httsp, http\\, hpp)
  4. Re-run validation after each fix: the loop bails on the first bad profile, so fix profiles one at a time

Example fix

# before
[providers.models.local]
uri = "localhost:11434"

# after
[providers.models.local]
uri = "http://localhost:11434"
Defensive patterns

Strategy: validation

Validate before calling

fn http_url_precheck(cfg: &zeroclaw_config::Config) -> Result<(), String> {
    for (name, profile) in &cfg.providers.models.entries {
        if let Some(uri) = &profile.uri {
            if uri.is_empty() { continue; }
            match reqwest::Url::parse(uri) {
                Ok(u) if matches!(u.scheme(), "http" | "https") => {}
                _ => return Err(format!("providers.models.{name}.uri must use http/https")),
            }
        }
    }
    Ok(())
}

Type guard

fn is_http_url(uri: &str) -> bool {
    reqwest::Url::parse(uri).is_ok_and(|u| matches!(u.scheme(), "http" | "https"))
}

Try / catch

if let Err(err) = config.validate() {
    if err.to_string().contains("must use http/https") {
        // give the named profile an explicit http(s) URL; local daemons -> http://localhost:PORT
    }
}

Prevention

When it happens

Trigger: Set a profile uri to "file:///models/foo.gguf", "unix:///tmp/llm.sock", "ws://host:8080", "localhost:11434" (no scheme), or a typo like "httsp://api.example.com".

Common situations: Pointing a profile at a local GGUF file or Unix socket, which this provider surface does not support; forgetting the scheme on local endpoints; using ws:// for streaming endpoints; template variables that render a bare host.

Related errors


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