Skip to content

fix(doctor): use query-param auth for Gemini in API-key probe - #26784

Closed
zhenyu707 wants to merge 1 commit into
NousResearch:mainfrom
zhenyu707:fix/doctor-gemini-query-param-auth
Closed

fix(doctor): use query-param auth for Gemini in API-key probe#26784
zhenyu707 wants to merge 1 commit into
NousResearch:mainfrom
zhenyu707:fix/doctor-gemini-query-param-auth

Conversation

@zhenyu707

Copy link
Copy Markdown

Summary

hermes doctor falsely reports ✗ gemini (invalid API key) for every user with a working GEMINI_API_KEY. Root cause: the generic _probe_apikey_provider in hermes_cli/doctor.py:1412–1490 sends Authorization: Bearer ${KEY} to /models, but the gemini profile's base_url=https://generativelanguage.googleapis.com/v1beta only accepts ?key=… query-param auth. Google's API gateway returns:

HTTP 401 ACCESS_TOKEN_TYPE_UNSUPPORTED
Request had invalid authentication credentials. Expected OAuth 2 access
token, login cookie or other valid authentication credential.

…which the generic 401 branch reports as (invalid API key). The credential is fine — hermes itself uses GeminiNativeClient which sends auth correctly. Only the doctor probe is wrong.

Fix

Detect generativelanguage.googleapis.com on the resolved URL (via the existing base_url_host_matches helper, same pattern used for api.kimi.com two lines up). When matched, rewrite the URL with ?key=… and drop the Authorization header so Google's gateway accepts the request.

10 lines, additive only — no change to behavior for any other provider.

Verification

Reproduced and verified against a real GEMINI_API_KEY:

# before
$ hermes doctor | grep -i gemini
  ✗ gemini               (invalid API key)

# Raw repro of the bug
$ curl -sS -H "Authorization: Bearer $KEY" \
    'https://generativelanguage.googleapis.com/v1beta/models' \
    -w '\nHTTP %{http_code}\n'
HTTP 401  →  ACCESS_TOKEN_TYPE_UNSUPPORTED

# Same key with query-param auth works
$ curl -sS \
    "https://generativelanguage.googleapis.com/v1beta/models?key=$KEY" \
    -w '\nHTTP %{http_code}\n'
HTTP 200  →  full model list returned

# generateContent also succeeds with the same key
$ curl -sS -X POST \
    "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=$KEY" \
    -H "Content-Type: application/json" \
    -d '{"contents":[{"parts":[{"text":"reply with one word ok"}]}],"generationConfig":{"maxOutputTokens":5}}'
{"candidates":[{"content":{"parts":[{"text":"ok"}],"role":"model"}, …}]}

# after the patch
$ hermes doctor | grep -i gemini
  ✓ gemini

Test plan

  • python -c "import ast; ast.parse(open('hermes_cli/doctor.py').read())" — syntax OK
  • Local smoke test: PYTHONPATH=. python -m hermes_cli.main doctor flips gemini from to against a real key
  • Other API-key providers (OpenRouter, DeepSeek, Alibaba/DashScope, Kimi, MiniMax, etc.) unaffected — branch only fires on generativelanguage.googleapis.com host
  • Existing tests in tests/hermes_cli/test_doctor.py and test_doctor_dedicated_provider_skip.py pass (please run in CI)

The shared `_probe_apikey_provider` sends `Authorization: Bearer ${KEY}` to
the provider's `/models` endpoint as a connectivity check. For the gemini
profile this hits `https://generativelanguage.googleapis.com/v1beta/models`,
which is a Google AI Studio surface and only accepts `?key=...` query-param
auth. Sending a Bearer header there returns:

  HTTP 401 ACCESS_TOKEN_TYPE_UNSUPPORTED
  "Request had invalid authentication credentials. Expected OAuth 2 access
   token, login cookie or other valid authentication credential."

The probe's generic 401 branch then reports `✗ gemini (invalid API key)`
for every user with a perfectly working `GEMINI_API_KEY` — `hermes` itself
calls Gemini via `GeminiNativeClient`, which uses the correct auth scheme.
Only the doctor probe is wrong.

Fix: detect the `generativelanguage.googleapis.com` host on the resolved
URL and switch to query-param auth (`?key=…`) before the request, dropping
the `Authorization` header so Google's API gateway accepts it.

Verified with a real `GEMINI_API_KEY`:
- Before: `✗ gemini               (invalid API key)`
- After:  `✓ gemini`

Both `generateContent` and `listModels` return 200 against the same key
when sent with query-param auth, confirming the credential was always
valid.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard provider/gemini Google Gemini (AI Studio, Cloud Code) labels May 16, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #21058 (canonical issue) / PR #20642 (canonical fix). This is the 8th+ duplicate fix for the same Gemini doctor Bearer-vs-query-param auth issue. See also competing PRs: #21490, #22286, #22468, #23364, #24033, #24266, #26067.

@zhenyu707

Copy link
Copy Markdown
Author

Closing — withdrawing this PR; will keep the fix as a local patch for now. No action needed from maintainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists provider/gemini Google Gemini (AI Studio, Cloud Code) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants