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. WhenView on GitHub (pinned to 7491200858)
Solutions
- Enter the API key for '{slug}' in Connections → LLM.
- Or switch `{role}_provider` to a slug that has a key, or to the managed OpenHuman backend.
- Confirm the slug matches the Connections entry exactly (case/spacing).
- 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
- Make provider selection validate key presence at save time, not request time.
- Keep slug names identical between config and Connections entries.
- Use the managed backend where no key management is desired.
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
- No usable credentials for '{slug}', which OpenHuman selected
- composio direct api key must not be empty
- OpenHuman uses the session JWT — keys are not configurable h
- OpenRouter key exchange failed (${response.status}).
- OpenRouter key exchange succeeded but no API key was returne
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/d35cac9c0e026ea4.
Report an issue: GitHub.