NousResearch/hermes-agent · error · ValueError
no usable api_key / token provider
Error message
no usable api_key / token provider
What it means
materialize_bearer_for_http() rejects its input because it is neither a recognized zero-arg callable token provider nor a non-empty string. This is a programming/validation error in whatever assembled the auth value for the Anthropic-style Foundry client — not an environmental failure.
Source
Thrown at agent/azure_identity_adapter.py:475
accept a ``Callable[[], str]`` for ``auth_token``. Instead,
:func:`build_bearer_http_client` returns an ``httpx.Client`` whose
request event hook calls this function and rewrites the
``Authorization`` header per request — and that client is passed to
the Anthropic SDK via ``http_client=...``. See
:func:`agent.anthropic_adapter.build_anthropic_client` for the
consumer.
Raises ``ValueError`` if ``value`` is not a callable token provider
or non-empty string.
"""
if is_token_provider(value):
token = value()
if not isinstance(token, str) or not token:
raise ValueError("token provider returned empty value")
return token
if isinstance(value, str) and value:
return value
raise ValueError("no usable api_key / token provider")
def build_bearer_http_client(token_provider: Callable[[], str], **httpx_kwargs: Any) -> Any:
"""Return an ``httpx.Client`` that mints a fresh Entra bearer JWT
per outbound request.
The Anthropic SDK (≤ 0.86.0 at the time of writing) stores
``api_key`` / ``auth_token`` as static strings and computes the
``Authorization`` header at construction time. To get per-request
token refresh (the Microsoft-recommended Foundry pattern for
callable bearer providers), we install an httpx ``request`` event
hook on a custom client and pass that client to the SDK via
``http_client=...``. The hook:
1. Calls :func:`materialize_bearer_for_http` to mint a fresh JWT
(azure-identity caches internally — this is cheap when the
cached token is still valid).
2. Strips any pre-set ``Authorization`` / ``api-key`` /View on GitHub (pinned to c896c09c42)
Solutions
- Provide either a non-empty static bearer string or a zero-arg callable returning the token.
- Check the config path feeding this value (e.g. azure/foundry auth settings) is actually set, not null/blank.
- Harden the call site to validate before building the client.
Example fix
# before
http = build_bearer_http_client(cfg.get("token")) # None when unset
# after
tok = cfg.get("token")
if not (isinstance(tok, str) and tok) and not callable(tok):
raise ValueError("azure auth token missing in config")
http = build_bearer_http_client(tok) Defensive patterns
Strategy: type-guard
Validate before calling
value = cfg.get("auth")
assert (isinstance(value, str) and value) or (callable(value) and value.__code__.co_argcount == 0), "auth must be a non-empty string or zero-arg callable" Type guard
def is_valid_bearer_source(v) -> bool:
return (isinstance(v, str) and len(v) > 0) or (callable(v) and getattr(v, "__code__", None) is not None and v.__code__.co_argcount == 0) Try / catch
try:
materialize_bearer_for_http(value)
except ValueError as e:
if "no usable api_key / token provider" in str(e):
raise ConfigError("auth value misconfigured — supply string or () -> str callable") from e Prevention
- Never pass config values straight into auth builders without shape validation.
- Default missing config to an explicit error at load time, not None at call time.
When it happens
Trigger: Passing None, an empty string, a number, or a one-arg callable where is_token_provider() is false (agent/azure_identity_adapter.py:475) — e.g. config fed `azure.auth_token: null` into the adapter.
Common situations: Missing config key defaulting to None; passing a static empty token when no Entra credential is configured; SDK version change altering what is_token_provider accepts.
Related errors
- Loopback callback missing authorization code
- Gateway token response missing access_token
- token provider returned empty value
- Preview mode — launching is disabled.
- no install root
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/0c8e254b2fd7bf3e.
Report an issue: GitHub.