Hmbown/CodeWhale · error · anyhow::Error

Runtime provider identity is invalid

Error message

Runtime provider identity is invalid

What it means

The resolved provider identity used to build the Runtime model-catalog URL is validated to contain only lowercase ASCII letters, digits, and hyphens. If the provider name (taken from the current provider iteration) contains other characters, the app-server rejects it before issuing a request, since it would produce an invalid/unintended provider route.

Solutions

  1. Rename the provider in the Runtime configuration to kebab-case (lowercase letters, digits, hyphens only).
  2. Check where the provider id originates (config file vs. catalog listing) and correct the source value.
  3. Verify the Runtime version's expected provider naming scheme.

Example fix

// before (provider config)
provider = "OpenAI_Main"
// after
provider = "openai-main"
Defensive patterns

Strategy: validation

Validate before calling

// validate provider ids are kebab-case before use
fn valid_provider(id: &str) -> bool {
    !id.is_empty() && id.bytes().all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'-')
}

Type guard

const isKebabProviderId = (s) => typeof s === 'string' && /^[a-z0-9-]+$/.test(s);

Prevention

When it happens

Trigger: The `current` provider identifier in the output-token capability scan fails the `ascii_lowercase | digit | '-'` byte check — e.g. contains uppercase, underscores, dots, or slashes.

Common situations: A provider configured with a name like `My_Provider` or `openai.com` instead of the kebab-case identifiers the Runtime expects.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at crates/app-server/src/lib.rs:1657

            .get("providers")
            .and_then(Value::as_array)
            .and_then(|providers| {
                providers
                    .iter()
                    .find(|provider| provider.get("id").and_then(Value::as_str) == Some(current))
            })
            .context("Runtime provider is unavailable")?;
        let model = requested_model
            .or_else(|| provider.get("default_model").and_then(Value::as_str))
            .context("maxOutputTokens requires an exact model")?;
        if model.trim().is_empty() || model.eq_ignore_ascii_case("auto") {
            bail!("maxOutputTokens requires an exact model");
        }
        if !current
            .bytes()
            .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-')
        {
            bail!("Runtime provider identity is invalid");
        }
        let mut cursor = None;
        let mut seen = std::collections::HashSet::new();
        loop {
            let mut url =
                reqwest::Url::parse(&format!("{}/v1/providers/{current}/models", self.base_url))?;
            url.query_pairs_mut().append_pair("limit", "250");
            if let Some(cursor) = cursor.as_deref() {
                url.query_pairs_mut().append_pair("cursor", cursor);
            }
            let catalog = self.request_json(self.authed(self.client.get(url))).await?;
            if let Some(entry) =
                catalog
                    .get("models")
                    .and_then(Value::as_array)
                    .and_then(|models| {
                        models
                            .iter()

View on GitHub (pinned to 73e0f67d83)