tinyhumansai/openhuman · error · anyhow::Error

No usable credentials for '{slug}', which OpenHuman selected

Error message

No usable credentials for '{slug}', which OpenHuman selected for the {} workload. Add a key for '{slug}' in Connections → LLM, set {}_provider to a provider that is configured, or enable the managed OpenHuman backend.

What it means

Direct-selection credential failure: the resolved cloud slug (chosen explicitly, not via local-chat fallback — hence the shorter message without the local-model clause) has no usable API key, and its entry uses Bearer or Anthropic auth which requires one. Same code path as the fallback variant (factory.rs:~2287, `implicit_fallback && key.trim().is_empty()`), distinguished by the diagnostic template chosen.

Source

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

    // 401 from the provider several layers later — exactly the baffling error
    // this diagnostic exists to replace.
    //
    // Scoped to the *implicit fallback* path deliberately. That is the case the
    // diagnostic is for: a local-chat user whose background role landed on a
    // BYOK slug they never configured. An explicitly routed provider keeps its
    // existing behaviour and is allowed to build without a stored key — callers
    // construct such models to probe or describe a provider before a key is
    // saved, and failing that at construction time would be a behaviour change
    // well beyond this diagnostic.
    //
    // Styles that carry no stored key (`OpenhumanJwt` injects a session JWT
    // downstream, `None` sends no auth header at all) are legitimately blank and
    // never trip this.
    if implicit_fallback
        && key.trim().is_empty()
        && matches!(entry.auth_style, AuthStyle::Bearer | AuthStyle::Anthropic)
    {
        anyhow::bail!("{}", missing_credentials());
    }
    let bearer_is_oauth = slug == "openai" && openai_bearer_is_oauth(config);
    let codex = resolve_openai_codex_routing(config, slug, &entry.endpoint, &key, bearer_is_oauth)
        .map_err(anyhow::Error::msg)?;

    Ok(CloudSlugResolution {
        entry,
        effective_model,
        key,
        codex,
    })
}

/// A `<slug>:<model>` BYOK cloud provider as a crate-native [`ChatModel`] — the
/// Native model for every configured cloud auth style, including the managed
/// `OpenhumanJwt` entry (issue #4727 Phase 3).
///
/// Returns `None` unless the role resolves to a **configured** cloud slug. When

View on GitHub (pinned to 7491200858)

Solutions

  1. Enter the API key for '{slug}' in Connections → LLM.
  2. Or switch `{role}_provider` to a slug that has a key, or to the managed OpenHuman backend.
  3. Confirm the slug matches the Connections entry exactly (case/spacing).
  4. If the key was just added, retry — resolution reads the credential store per request.

Example fix

# config — before
chat_provider = "openai"
# (no key stored for openai)

# after: either store the key via Connections -> LLM, or
chat_provider = "openhuman"   # managed backend, no key needed
Defensive patterns

Strategy: validation

Validate before calling

let key = auth.get_provider_bearer_token(slug, None)?.unwrap_or_default();
if key.trim().is_empty() && matches!(entry.auth_style, AuthStyle::Bearer | AuthStyle::Anthropic) {
    return Err(anyhow::anyhow!("missing key for {slug} — add it before selecting this provider"));
}

Type guard

fn provider_ready(slug: &str, entry: &CloudProviderEntry, auth: &AuthService) -> bool {
    !matches!(entry.auth_style, AuthStyle::Bearer | AuthStyle::Anthropic)
        || auth.get_provider_bearer_token(slug, None)
               .ok().flatten()
               .is_some_and(|k| !k.trim().is_empty())
}

Prevention

When it happens

Trigger: A role explicitly configured to a BYOK cloud slug (e.g. `anthropic:claude-sonnet-4-6`) where the stored key for that slug is empty, while the entry's auth_style is Bearer/Anthropic.

Common situations: Provider selected in Settings before its key was entered; key deleted or lost after a workspace/profile migration; key saved under a renamed slug.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


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