Gemini auth method fixes in doctor/discovery

NousResearch/hermes-agent · cluster 19837 · agent

Data as of

4 open items. Fix merged in #11961. Check it covers your case.

The short answer

2open issues
2open PRs
30items grouped
Known?
Yes. 30 related items grouped here, 10 issues already closed.
Fix event
A fix was merged to main in PR #11961. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this partially resolved, deciding PR #22801. That is separate from the fix event.
Still open
2 issues and 2 PRs.

These issues and PRs center on incorrect authentication formats (Bearer token vs. API key query param or x-goog-api-key header) being used when probing or discovering Gemini endpoints in the doctor command and model discovery. Multiple related fixes address false-positive invalid-key errors and routing to the correct Gemini API endpoint.

Open issues2

  • Issue#48689`hermes doctor` reports stale `ui-tui` npm vulnerability and false-positive `gemini (invalid API key)`
  • Issue#62259Gemini live model discovery fails — native /v1beta endpoint rejects Bearer auth (falls back to 4 static models)

Open PRs2

  • PR#48752fix: reduce stale doctor audit and oauth noise
  • PR#116509fix(providers): complete native Gemini ListModels discovery

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #11961 fix(gemini): route Google AI Studio auth via x-goog-api-key header (#7893)

    merged to main

    files: agent/auxiliary_client.py, run_agent.py, scripts/release.py, tests/hermes_cli/test_gemini_provider.py

  • #22801 fix(doctor): skip pluggable provider profiles when a dedicated check exists (salvage #22529)

    merged to main

    files: hermes_cli/doctor.py, tests/hermes_cli/test_doctor_dedicated_provider_skip.py

    Show the diff
    • hermes_cli/doctor.py
      @@ -245,15 +245,31 @@ def _build_apikey_providers_list() -> list:
           }
           for _label, _canonical in _name_to_canonical.items():
               _known_canonical.add(_canonical)
      +    # Providers that already have a dedicated health check above the generic
      +    # API-key loop (with custom headers/auth). Skip their pluggable profiles
      +    # here so the generic Bearer-auth loop doesn't run a duplicate, broken
      +    # check (e.g. Anthropic native API requires x-api-key, not Bearer).
      +    _dedicated_canonical = {"anthropic", "openrouter", "bedrock"}
      +    _known_canonical.update(_dedicated_canonical)
           try:
               from providers import list_providers
               from providers.base import ProviderProfile as _PP
      +        try:
      +            from hermes_cli.providers import normalize_provider as _normalize_provider
      +        except Exception:  # pragma: no cover - normalization is best-effort
      +            def _normalize_provider(_name: str) -> str:
      +                return (_name or "").strip().lower()
               for _pp in list_providers():
                   if not isinstance(_pp, _PP) or _pp.auth_type != "api_key" or not _pp.env_vars:
                       continue
                   _label = _pp.display_name or _pp.name
                   if _label in _known_names or _pp.name in _known_canonical:
                       continue
      +            _candidates = {_normalize_provider(_pp.name)}
      +            for _alias in (_pp.aliases or ()):
      +                _candidates.add(_normalize_provider(_alias))
      +            if _candidates & _dedicated_canonical:
      +                continue
                   # Separate API-key vars from base-URL override vars — the health-check
                   # loop sends the first found value as Authorization: Bearer, so a URL
                   # string must never be picked.
    • tests/hermes_cli/test_doctor_dedicated_provider_skip.py
      @@ -0,0 +1,50 @@
      +"""Regression: hermes doctor must not run a generic Bearer-auth health
      +check for providers that already have a dedicated check (Anthropic,
      +OpenRouter, Bedrock).
      +
      +Anthropic's native API requires `x-api-key` + `anthropic-version` headers;
      +the generic loop sends `Authorization: Bearer ...` which Anthropic answers
      +with HTTP 404. The dedicated check at hermes_cli/doctor.py already covers
      +Anthropic with the right headers, so the pluggable profile must be
      +skipped by `_build_apikey_providers_list()`.
      +
      +See: NousResearch/hermes-agent#22346
      +"""
      +
      +from __future__ import annotations
      +
      +
      +def test_build_apikey_providers_list_skips_dedicated_check_providers():
      +    from hermes_cli import doctor
      +
      +    # Force a rebuild — the module caches the list on first call.
      +    doctor._APIKEY_PROVIDERS_CACHE = None
      +    entries = doctor._build_apikey_providers_list()
      +
      +    # Tuple shape: (display_name, env_vars, default_url, base_env, supports_health_check)
      +    names = {entry[0].lower() for entry in entries}
      +    assert not any("anthropic" in name for name in names), (
      +        f"Anthropic provider profile leaked into generic Bearer-auth health "
      +        f"check loop. Dedicated check above already covers it with "
      +        f"x-api-key headers. Got entries: {sorted(names)}"
      +    )
      +    assert not any("openrouter" in name for name in names), (
      +        f"OpenRouter has a dedicated check; generic loop must skip it. "
      +        f"Got: {sorted(names)}"
      +    )
      +    assert not any("bedrock" in name for name in names), (
      +        f"Bedrock uses AWS SDK creds, not Bearer auth; generic loop must skip. "
      +        f"Got: {sorted(names)}"
      +    )
      +
      +
      +def test_build_apikey_providers_list_includes_non_dedicated_providers():
      +    """Sanity guard: the skip-set must not strip every provider."""
      +    from hermes_cli import doctor
      +
      +    doctor._APIKEY_PROVIDERS_CACHE = None
      +    entries = doctor._build_apikey_providers_list()
      +
      +    names = {entry[0] for entry in entries}
      +    assert "DeepSeek" in names
      +    assert "Z.AI / GLM" in names

14 PRs closed without merging

From the close comments: superseded by another PR 5 · done elsewhere 3 · duplicate 3 · merged via another change 1 · other 2

  • #19854 fix(doctor): report google/gemini API key status in connectivity checks · superseded by another PR → #20204
  • #20204 doctor: report Google Gemini API connectivity · done elsewhere
  • #20935 fix(doctor): skip /models health-check for Alibaba dedicated tiers · other → #20642
  • #21490 fix(doctor): validate Gemini keys with Google auth · done elsewhere → 364a1dd
  • #22232 fix: align doctor provider health checks · other → 0c233e7, 6b21a93
Show 9 more
  • #22286 fix(doctor): probe native gemini keys correctly · done elsewhere
  • #22367 fix(doctor): skip duplicate anthropic Bearer-auth check · superseded by another PR → #22529, #22346
  • #22512 fix(cli): skip dedicated-check providers in apikey loop · superseded by another PR → #22801, #22529
  • #22529 fix(doctor): skip pluggable provider profiles when a dedicated check exists (#22346) · merged via another change → #22801
  • #23364 fix(doctor): use ?key= auth for Gemini API key validation · superseded by another PR → #11961
  • #25139 fix: use Gemini API key query auth in doctor · superseded by another PR
  • #26784 fix(doctor): use query-param auth for Gemini in API-key probe · duplicate → #21058, #20642, #21490, #22286, #22468, #23364, #24033, #24266, #26067
  • #26922 fix(doctor): use x-goog-api-key for Gemini connectivity probe (#26623) · duplicate → #20642, #22468, #22489, #24266, #25883, #26067
  • #62267 fix(providers): use native query-param auth for Gemini model discovery (#62259) · duplicate → #42693, #62259
Closed issues · 10
  • Closed#19837[Bug]: cli doctor API Connectivity missing google api key/gemini api key
  • Closed#21058hermes doctor: Gemini healthcheck fails with 401 due to Bearer-token auth incompatibility
  • Closed#21481[Bug]: hermes doctor falsely reports valid Google AI Studio Gemini API key as invalid
  • Closed#22223doctor should honor provider base URL overrides for Xiaomi health checks
  • Closed#22346hermes doctor: duplicate `anthropic` check fails with HTTP 404 (wrong auth header in pluggable provider check)
  • Closed#23354Hermes Doctor flags Google Gemini API key as invalid even when the key works
  • Closed#25108[Bug]: hermes doctor validates Gemini API keys with Bearer auth instead of ?key=
  • Closed#26284hermes doctor reports false positive "invalid API key" for Google Gemini
  • Closed#26623[Bug]: bug(cli): hermes doctor falsely reports Google Gemini API key as invalid (HTTP 401 due to OpenAI auth format)
  • Closed#27310doctor should validate Gemini API keys with Gemini native auth instead of generic Bearer probe
How this cluster was grouped
  • Link evidence (partly structural links): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
  • Members outside that structural core may belong to a different underlying problem.
  • Pairwise link density 0.07: the share of item 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.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
agent
Merged PRs
#11961, #22801
Closed issues
10
Attempts
14 PRs closed without merging
Fix link checked
9 May 2026

For your agent

The same facts, typed.