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. Your chat model is local ('{}') and does not serve this workload, so it fell back to your cloud provider — but '{slug}' has no API key configured. 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

Implicit-fallback credential failure: the user's chat model is local, so this workload (e.g. a cloud-only role) fell back to a cloud slug that has NO stored API key, and the entry's auth style is Bearer/Anthropic (styles that require a stored key — OpenhumanJwt and None are exempt). The long message (from `missing_credentials()`) explains the local-chat fallback chain and offers three remedies. Triggered at factory.rs:~2287 when `implicit_fallback && key.is_empty()`.

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. Add an API key for '{slug}' under Connections → LLM in Settings.
  2. Or set the `{role}_provider` for the failing workload to a provider that IS configured (or a local model that serves it).
  3. Or enable the managed OpenHuman backend, which needs no user key.
  4. Verify the slug spelling — a typo'd slug will always look key-less.

Example fix

# settings path: Connections -> LLM -> add key for the slug named in the error
# or config: point the workload at a configured provider
# before
summary_provider = "mycustom-slug"
# after
summary_provider = "ollama:llama3.1:8b"
Defensive patterns

Strategy: validation

Validate before calling

// Before routing a cloud-only workload while chat is local:
let key = auth.get_provider_bearer_token(&slug, None)?.unwrap_or_default();
let needs_key = matches!(entry.auth_style, AuthStyle::Bearer | AuthStyle::Anthropic);
if key.trim().is_empty() && needs_key {
    return prompt_add_key(&slug); // or pick a configured provider
}

Type guard

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

Prevention

When it happens

Trigger: Primary chat set to a local model (Ollama etc.) while a secondary workload (title generation, embeddings, summaries) implicitly falls back to the configured cloud provider slug, whose API key was never entered in Connections → LLM.

Common situations: New users who run local chat but never added a cloud key; a key stored under a different slug name than the one configured; keys cleared by a workspace reset.

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/4183a16b5cdff4a4. Report an issue: GitHub.