# NousResearch/hermes-agent · OpenRouter exhausted auxiliary key logging clarification

## Open now

- Nothing open on GitHub.

A bug was reported where an exhausted OpenRouter auxiliary API key was incorrectly logged as the key not being set. These members address clarifying the error message to accurately reflect the exhausted credential state.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #14739. Verify it addresses your case.
- **Recommended:** read PR #14739 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `resolved` · deciding PR(s): `pr-14739`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #14618: \[Bug\]: In auxiliary client, an exhausted OpenRouter key is logged as key not being set

## Prior & competing PRs

- **#14739: fix(agent): clarify exhausted OpenRouter auxiliary credentials (salvage #14646)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `agent/auxiliary_client.py`, `tests/agent/test_auxiliary_client.py`
  - fix hunks:
  - `agent/auxiliary_client.py`

    ```diff
    @@ -916,6 +916,19 @@ def _try_openrouter() -> Tuple[Optional[OpenAI], Optional[str]]:
                        default_headers=_OR_HEADERS), _OPENROUTER_MODEL
     
     
    +def _describe_openrouter_unavailable() -> str:
    +    """Return a more precise OpenRouter auth failure reason for logs."""
    +    pool_present, entry = _select_pool_entry("openrouter")
    +    if pool_present:
    +        if entry is None:
    +            return "OpenRouter credential pool has no usable entries (credentials may be exhausted)"
    +        if not _pool_runtime_api_key(entry):
    +            return "OpenRouter credential pool entry is missing a runtime API key"
    +    if not str(os.getenv("OPENROUTER_API_KEY") or "").strip():
    +        return "OPENROUTER_API_KEY not set"
    +    return "no usable OpenRouter credentials found"
    +
    +
     def _try_nous(vision: bool = False) -> Tuple[Optional[OpenAI], Optional[str]]:
         # Check cross-session rate limit guard before attempting Nous —
         # if another session already recorded a 429, skip Nous entirely
    ```

    ```diff
    @@ -1627,8 +1640,10 @@ def _wrap_if_needed(client_obj, final_model_str: str, base_url_str: str = ""):
         if provider == "openrouter":
             client, default = _try_openrouter()
             if client is None:
    -            logger.warning("resolve_provider_client: openrouter requested "
    -                           "but OPENROUTER_API_KEY not set")
    +            logger.warning(
    +                "resolve_provider_client: openrouter requested but %s",
    +                _describe_openrouter_unavailable(),
    +            )
                 return None, None
             final_model = _normalize_resolved_model(model or default, provider)
             return (_to_async_client(client, final_model) if async_mode
    ```
  - `tests/agent/test_auxiliary_client.py`

    ```diff
    @@ -447,6 +447,34 @@ def test_explicit_anthropic_api_key(self, monkeypatch):
                 adapter = client.chat.completions
                 assert adapter._is_oauth is False
     
    +    def test_explicit_openrouter_pool_exhausted_logs_precise_warning(self, monkeypatch, caplog):
    +        monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
    +        with patch("agent.auxiliary_client._select_pool_entry", return_value=(True, None)):
    +            with caplog.at_level(logging.WARNING, logger="agent.auxiliary_client"):
    +                client, model = resolve_provider_client("openrouter")
    +        assert client is None
    +        assert model is None
    +        assert any(
    +            "credential pool has no usable entries" in record.message
    +            for record in caplog.records
    +        )
    +        assert not any(
    +            "OPENROUTER_API_KEY not set" in record.message
    +            for record in caplog.records
    +        )
    +
    +    def test_explicit_openrouter_missing_env_keeps_not_set_warning(self, monkeypatch, caplog):
    +        monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
    +        with patch("agent.auxiliary_client._select_pool_entry", return_value=(False, None)):
    +            with caplog.at_level(logging.WARNING, logger="agent.auxiliary_client"):
    +                client, model = resolve_provider_client("openrouter")
    +        assert client is None
    +        assert model is None
    +        assert any(
    +            "OPENROUTER_API_KEY not set" in record.message
    +            for record in caplog.records
    +        )
    +
     class TestGetTextAuxiliaryClient:
         """Test the full resolution chain for get_text_auxiliary_client."""
     
    ```
- **#14646: fix(agent): clarify exhausted OpenRouter auxiliary credentials**. closed without merge
  - maintainer direction: category `silent_close`; implication `active`

## Fix status

- Merged to main in PR #14739 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-04-23`. This confirmation is old and may be out of date (a revert/reopen would not have invalidated it here); re-verify.
