tinyhumansai/openhuman · error · anyhow::Error

[chat-factory] model '{}' is an abstract tier for role '{}',

Error message

[chat-factory] model '{}' is an abstract tier for role '{}', but cloud provider slug '{}' has no concrete default_model configured. Set cloud_providers[].default_model to a provider-native model id (e.g. deepseek-v4-pro).

What it means

The effective model for a role resolved to an abstract tier name (something `is_abstract_tier_model` recognizes, e.g. a tier like 'fast'/'balanced' rather than a provider-native model id). The factory tried to remap it to a concrete model via the entry's `default_model`, but that field is missing or itself abstract/blank, so it bails (factory.rs:~2205-2216).

Source

Thrown at src/openhuman/inference/provider/factory.rs:2216

    }

    if entry.auth_style != AuthStyle::OpenhumanJwt && is_abstract_tier_model(&effective_model) {
        if let Some(default_model) = entry
            .default_model
            .as_deref()
            .map(str::trim)
            .filter(|m| !m.is_empty() && !is_abstract_tier_model(m))
        {
            log::info!(
                "[providers][chat-factory] role={} slug={} remapping abstract model {} -> {}",
                role,
                slug,
                effective_model,
                default_model
            );
            effective_model = default_model.to_string();
        } else {
            anyhow::bail!(
                "[chat-factory] model '{}' is an abstract tier for role '{}', \
                 but cloud provider slug '{}' has no concrete default_model configured. \
                 Set cloud_providers[].default_model to a provider-native model id (e.g. deepseek-v4-pro).",
                effective_model,
                role,
                slug
            );
        }
    }

    log::info!(
        "[providers][chat-factory] role={} slug={} model={} endpoint_host={}",
        role,
        slug,
        effective_model,
        redact_endpoint(&entry.endpoint)
    );

View on GitHub (pinned to 7491200858)

Solutions

  1. Set `cloud_providers[].default_model` to a provider-native model id, e.g. `deepseek-v4-pro`.
  2. Or bypass the tier entirely: put a concrete model in the provider string (`slug:<concrete-model>`).
  3. Check the entry with the slug named in the message — the fix is scoped to that entry.
  4. Retry the request after saving config.

Example fix

# config.toml — before
[[cloud_providers]]
slug = "deepseek"
default_model = "fast"

# after
[[cloud_providers]]
slug = "deepseek"
default_model = "deepseek-v4-pro"
Defensive patterns

Strategy: validation

Validate before calling

fn concrete_model_configured(entry: &CloudProviderEntry, effective_model: &str) -> bool {
    if !is_abstract_tier_model(effective_model) { return true; }
    entry.default_model.as_deref()
        .map(|m| !m.trim().is_empty() && !is_abstract_tier_model(m))
        .unwrap_or(false)
}

Prevention

When it happens

Trigger: A role configured with an abstract tier model (e.g. `fast`, `quality`) on a custom `cloud_providers` slug whose entry lacks a concrete `default_model`, or whose `default_model` is another abstract tier rather than a real model id like `deepseek-v4-pro`.

Common situations: Copying a provider config from the managed backend (where tiers are valid) to a BYOK slug (where they are not); setting `default_model = "fast"` by mistake; deleting the `default_model` line while editing an entry.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/4759a881e6d218aa. Report an issue: GitHub.