Hmbown/CodeWhale · error · anyhow::Error

Codewhale account API base URL must not contain credentials

Error message

Codewhale account API base URL must not contain credentials

What it means

validate_api_base rejects any account API base URL containing userinfo (user:password@host) before it is ever used. Credentials embedded in URLs leak via logs, history, and error messages, and none of the cloud endpoints accept them, so this is an early hard stop with a clear message.

Source

Thrown at crates/cli/src/cloud.rs:764

        writeln!(out, "Email: {}", printable(&user.email))?;
    }
    if !user.plan.trim().is_empty() {
        writeln!(out, "Plan: {}", printable(&user.plan))?;
    }
    writeln!(out, "Profile: {}", printable(profile))?;
    writeln!(out, "API: {api_base}")?;
    Ok(())
}

struct ValidatedApiBase {
    url: Url,
    display: String,
}

fn validate_api_base(value: &str) -> Result<ValidatedApiBase> {
    let mut url = Url::parse(value.trim()).context("invalid Codewhale account API base URL")?;
    if !url.username().is_empty() || url.password().is_some() {
        bail!("Codewhale account API base URL must not contain credentials");
    }
    if url.query().is_some() || url.fragment().is_some() {
        bail!("Codewhale account API base URL must not contain a query or fragment");
    }
    if !matches!(url.path(), "" | "/") {
        bail!("Codewhale account API base URL must be an origin without a path");
    }
    let host = url
        .host_str()
        .ok_or_else(|| anyhow!("Codewhale account API base URL must include a host"))?;
    let allowed = url.scheme() == "https" || (url.scheme() == "http" && is_loopback_host(host));
    if !allowed {
        bail!(
            "Codewhale account API base URL must use HTTPS (loopback HTTP is allowed for testing)"
        );
    }
    url.set_path("/");
    let display = url.as_str().trim_end_matches('/').to_string();

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Remove the userinfo portion: use a plain origin such as https://api.codewhale.net.
  2. If the endpoint needs auth, that belongs in headers/tokens, not the base URL (Codewhale cloud auth is the OAuth session, not URL credentials).
  3. Check both the --api-base flag and the stored profile config for the stray credentials.

Example fix

# before
--api-base https://user:secret@api.codewhale.net

# after
--api-base https://api.codewhale.net
Defensive patterns

Strategy: validation

Validate before calling

// Validate before passing to the CLI
fn base_url_is_safe(value: &str) -> bool {
    url::Url::parse(value).map(|u| u.username().is_empty() && u.password().is_none()).unwrap_or(false)
}

Type guard

fn is_credential_free_origin(u: &url::Url) -> bool {
    u.username().is_empty() && u.password().is_none()
        && matches!(u.path(), "" | "/")
        && u.query().is_none() && u.fragment().is_none()
}

Prevention

When it happens

Trigger: Passing --api-base or config like https://user:pass@api.codewhale.net or http://admin:x@localhost:9000; copy-pasting a URL that includes basic-auth userinfo.

Common situations: Users templating authenticated internal URLs into the api-base setting, docs/examples that include userinfo placeholders, muscle memory from tools that support basic auth in the URL.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/5b6748c080e343d5. Report an issue: GitHub.