Hmbown/CodeWhale · error · anyhow::Error

Refusing insecure base URL

Error message

Refusing insecure base URL '{display_base_url}'.

Loopback hosts (localhost, 127.0.0.1, [::1]) are auto-allowed.
For one trusted local provider (LAN, llama.cpp on a private IP, etc.) set
`allow_insecure_http = true` under its `[providers.<name>]` table in config.toml.
To allow it for every provider in this shell instead, set the env var
`{ALLOW_INSECURE_HTTP_ENV}=1` and re-run.

What it means

The HTTP client refuses to connect to a provider whose base URL uses plain http:// on a non-loopback host. Loopback hosts (localhost, 127.0.0.1, [::1]) are auto-allowed; anything else would send prompts and API keys in cleartext, so startup fails with this message explaining the three opt-in mechanisms. It is a deliberate security guard against credential leakage over unencrypted LAN traffic.

Solutions

  1. Use https:// for the provider base URL (preferred fix).
  2. Use a loopback host (localhost / 127.0.0.1) with a port-forward or tunnel so the auto-allow applies.
  3. Set `allow_insecure_http = true` under the specific `[providers.<name>]` table in config.toml for that one trusted provider.
  4. Set the ALLOW_INSECURE_HTTP_ENV env var to 1 to allow insecure HTTP for every provider in this shell (broadest, least safe).

Example fix

// config.toml — before
[providers.llamacpp]
base_url = "http://192.168.1.50:8080"
// after
[providers.llamacpp]
base_url = "http://192.168.1.50:8080"
allow_insecure_http = true
Defensive patterns

Strategy: validation

Validate before calling

let url = url::Url::parse(&base_url)?;
let insecure = url.scheme() == "http"
    && !matches!(url.host_str(), Some("localhost") | Some(h) if h.parse::<std::net::IpAddr>().map(|i| i.is_loopback()).unwrap_or(false));
if insecure && !provider_allow_insecure_http && std::env::var("CODEWHALE_ALLOW_INSECURE_HTTP") != Ok("1".into()) {
    // switch to https / loopback, or set the opt-in before startup
}

Try / catch

match build_client(&provider) {
    Ok(c) => c,
    Err(e) if e.to_string().contains("Refusing insecure base URL") => {
        eprintln!("{e}"); // the message lists the exact opt-in options
        std::process::exit(2);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Configuring a provider with an http:// base URL pointing at a LAN/private-IP host (e.g. http://192.168.1.50:8080) and starting a session, without any insecure-HTTP opt-in.

Common situations: Pointing Codewhale at a local llama.cpp/Ollama/LM Studio instance by its LAN IP; docker/VM setups where the model server is reachable only via a private address; typo-ing https:// as http://.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/49827fd94a308e27. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client.rs:1112

        );
        return Ok(());
    }

    if parsed.scheme() == "http"
        && std::env::var(ALLOW_INSECURE_HTTP_ENV)
            .or_else(|_| std::env::var(LEGACY_ALLOW_INSECURE_HTTP_ENV))
            .ok()
            .as_deref()
            .is_some_and(|v| v == "1" || v.eq_ignore_ascii_case("true"))
    {
        logging::warn(format!(
            "Using insecure HTTP base URL because {ALLOW_INSECURE_HTTP_ENV} is set"
        ));
        return Ok(());
    }

    if parsed.scheme() == "http" {
        anyhow::bail!(
            "Refusing insecure base URL '{display_base_url}'.\n\
             \n\
             Loopback hosts (localhost, 127.0.0.1, [::1]) are auto-allowed.\n\
             For one trusted local provider (LAN, llama.cpp on a private IP, etc.) set\n\
             `allow_insecure_http = true` under its `[providers.<name>]` table in config.toml.\n\
             To allow it for every provider in this shell instead, set the env var\n\
             `{ALLOW_INSECURE_HTTP_ENV}=1` and re-run.",
        );
    }

    anyhow::bail!(
        "Refusing base URL '{display_base_url}': only HTTPS (or explicitly allowed HTTP) URLs are supported.",
    )
}

/// Mask credentials in a URL for display.
///
/// Delegates to the single shared implementation in

View on GitHub (pinned to 73e0f67d83)