Skip to content

[Bug]: auth.json credential cache ignores .env changes — stale key persists #18254

@franksong2702

Description

@franksong2702

Bug Description

When OPENROUTER_API_KEY (or other env-seeded credentials) is updated in ~/.hermes/.env, the cached credential in auth.json (credential_pool.openrouter) is not invalidated. Hermes continues using the old cached key, resulting in silent 401 errors.

Steps to Reproduce

  1. Set OPENROUTER_API_KEY=test-key-fresh in ~/.hermes/.env and start Hermes
  2. Update ~/.hermes/.env with a valid key (e.g. sk-or-...b854)
  3. Restart Hermes gateway
  4. Try to use an OpenRouter model → HTTP 401 "Missing Authentication header"
  5. Check auth.json → credential still has access_token: "test-key-fresh"

Root Cause

The credential pool seeds from env vars via _seed_from_env() in agent/credential_pool.py. It calls get_env_value() which checks os.environ FIRST, then falls back to ~/.hermes/.env:

def get_env_value(key: str) -> Optional[str]:
    """Get a value from ~/.hermes/.env or environment."""
    if key in os.environ:
        return os.environ[key]     # <-- takes priority over .env!
    env_vars = load_env()
    return env_vars.get(key)

If any parent process (e.g. Codex CLI, test script) has exported OPENROUTER_API_KEY=test-key-fresh, that stale value shadows the actual key in .env. The credential pool then caches this stale value in auth.json and never re-reads .env.

The fix should ensure that ~/.hermes/.env is the authoritative source for Hermes config, with os.environ only as a secondary fallback — not the override.

Expected Behavior

  • Updating a key in ~/.hermes/.env + restarting Hermes should use the new key
  • auth.json cache should reflect the .env file content, not stale os.environ values from parent shell processes

Actual Behavior

  • auth.json retains a snapshot of whichever value was in os.environ at the time of first load
  • Changing .env does not update the cached credential
  • Users get 401 errors with no indication that the cache is stale

Environment

  • Hermes v0.12.0 (2026.4.30)
  • macOS (local CLI)
  • Tested with OpenRouter provider

Diagnostic Command

python3 -c "
import json
a = json.load(open(\"/Users/xuefusong/.hermes/auth.json\"))
c = a[\"credential_pool\"][\"openrouter\"][0]
print(f\"Cached key: {c[\"access_token\"]}\")
print(f\"Source: {c[\"source\"]}\")
print(f\"Status: {c.get(\"last_status\")}\")
import os
print(f\"Env var: {os.environ.get(\"OPENROUTER_API_KEY\", \"(not set)\")[:20]}...\")
" 2>&1

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — major feature broken, no workaroundarea/authAuthentication, OAuth, credential poolsarea/configConfig system, migrations, profilescomp/agentCore agent loop, run_agent.py, prompt builderprovider/openrouterOpenRouter aggregatortype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions