hermes - 💡(How to fix) Fix [Feature]: Setup templates reference api_key_file: / *_API_KEY_FILE env vars but config schema doesn't recognize them — silently ignored, leading to "I rotated the key" confusion [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#18709Fetched 2026-05-03 04:54:46
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
labeled ×4

Root Cause

Operators following best practices for secret hygiene (separate file, mode 0600, reference from a less-protected config) reasonably write:

providers:
  openai:
    api_key_file: /etc/hermes/secrets/openai.key

or in env:

OPENAI_API_KEY_FILE=/etc/hermes/secrets/openai.key

Both silently fail. The operator is then forced to fall back to one of:

  1. Plaintext api_key: in config.yaml (which hermes setup writes directly into the file by default, including in model.api_key AND custom_providers[*].api_key — two locations for the same value)
  2. OPENAI_API_KEY= directly in ~/.hermes/.env (where it persists across rotations and silently overrides systemd-injected new values — see issue #N)

Both options put the secret material somewhere it doesn't belong, which is exactly what api_key_file was meant to prevent.

Code Example

WARNING hermes_cli.config: providers.openai: unknown config keys ignored: api_key_file
WARNING hermes_cli.config: providers.anthropic: unknown config keys ignored: api_key_file
WARNING hermes_cli.config: providers.gemini: unknown config keys ignored: api_key_file

---

grep -rn 'api_key_file' hermes-agent/ --include='*.py' | grep -v venv
# 0 results

grep -rn -E 'OPENAI_API_KEY_FILE|ANTHROPIC_API_KEY_FILE|GEMINI_API_KEY_FILE|GOOGLE_API_KEY_FILE' \
    hermes-agent/ --include='*.py' | grep -v venv
# 0 results

---

providers:
  openai:
    api_key_file: /etc/hermes/secrets/openai.key

---

OPENAI_API_KEY_FILE=/etc/hermes/secrets/openai.key

---

WARNING: api_key_file is not supported. Set api_key: <value> or
  OPENAI_API_KEY environment variable instead. The current value is
  being read from <actual source>.

---
RAW_BUFFERClick to expand / collapse

Problem or Use Case

The providers.<provider>.api_key_file: field in config.yaml and the OPENAI_API_KEY_FILE / ANTHROPIC_API_KEY_FILE / GEMINI_API_KEY_FILE / GOOGLE_API_KEY_FILE environment variables appear in deployment templates and at least some setup workflows, but are not read by any code path in Hermes 0.12.0.

The result is a startup warning that's easy to miss in errors.log:

WARNING hermes_cli.config: providers.openai: unknown config keys ignored: api_key_file
WARNING hermes_cli.config: providers.anthropic: unknown config keys ignored: api_key_file
WARNING hermes_cli.config: providers.gemini: unknown config keys ignored: api_key_file

Verification:

grep -rn 'api_key_file' hermes-agent/ --include='*.py' | grep -v venv
# 0 results

grep -rn -E 'OPENAI_API_KEY_FILE|ANTHROPIC_API_KEY_FILE|GEMINI_API_KEY_FILE|GOOGLE_API_KEY_FILE' \
    hermes-agent/ --include='*.py' | grep -v venv
# 0 results

Why this matters

Operators following best practices for secret hygiene (separate file, mode 0600, reference from a less-protected config) reasonably write:

providers:
  openai:
    api_key_file: /etc/hermes/secrets/openai.key

or in env:

OPENAI_API_KEY_FILE=/etc/hermes/secrets/openai.key

Both silently fail. The operator is then forced to fall back to one of:

  1. Plaintext api_key: in config.yaml (which hermes setup writes directly into the file by default, including in model.api_key AND custom_providers[*].api_key — two locations for the same value)
  2. OPENAI_API_KEY= directly in ~/.hermes/.env (where it persists across rotations and silently overrides systemd-injected new values — see issue #N)

Both options put the secret material somewhere it doesn't belong, which is exactly what api_key_file was meant to prevent.

Suggested fix — pick one

Option A — implement what users already expect

Add api_key_file: to the config schema. On load, resolve to file contents (string-strip trailing newline). Apply to all providers, both model.api_key_file and providers.<name>.api_key_file and custom_providers[*].api_key_file.

For env: if OPENAI_API_KEY is unset but OPENAI_API_KEY_FILE is set and points to a readable file, read its contents into os.environ['OPENAI_API_KEY']. This matches the pattern of Docker secrets, Kubernetes secrets-as-files, systemd's LoadCredential=, and dozens of other tools.

Estimated diff: ~20-30 lines in hermes_cli/config.py and similar in env loading.

Option B — be explicit that it's unsupported

If the design decision is "we don't support file-based secrets":

  • Remove api_key_file: from any setup-generated configs and deployment guides
  • Remove *_API_KEY_FILE env var references from any docs
  • Upgrade the warning from unknown config keys ignored: api_key_file to:
    WARNING: api_key_file is not supported. Set api_key: <value> or
    OPENAI_API_KEY environment variable instead. The current value is
    being read from <actual source>.

The current state — silent ignore + persistent template — strongly implies it works, leading directly to issue #N (above).

Environment

  • Hermes 0.12.0 (hermes-agent commit f903ceec)
  • Reproducible on fresh hermes setup install

Proposed Solution

Alternatives Considered

No response

Feature Type

New tool

Scope

None

Contribution

  • I'd like to implement this myself and submit a PR

Debug Report (optional)

extent analysis

TL;DR

Implement api_key_file support in Hermes by adding it to the config schema and loading its contents, or explicitly remove and document its unavailability to prevent silent failures.

Guidance

  • Review the hermes_cli/config.py file to understand the current config schema and loading mechanism.
  • Consider implementing Option A by adding api_key_file to the config schema and resolving its contents on load.
  • If choosing Option B, remove api_key_file references from setup-generated configs, deployment guides, and documentation to avoid confusion.
  • Verify the fix by checking for the presence or absence of warnings related to api_key_file in the errors.log file.

Example

# Example of how api_key_file could be implemented in hermes_cli/config.py
import os

# ...

def load_config(config_file):
    # ...
    if 'api_key_file' in config:
        api_key_file = config['api_key_file']
        with open(api_key_file, 'r') as f:
            api_key = f.read().strip()
        # Use the loaded api_key
    # ...

Notes

The choice between Option A and Option B depends on the desired behavior and security requirements of the Hermes application. Implementing Option A provides a secure way to handle API keys, while Option B explicitly documents the unavailability of this feature.

Recommendation

Apply workaround by implementing Option A, as it provides a secure and expected behavior for handling API keys. This approach aligns with best practices for secret hygiene and prevents silent failures.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix [Feature]: Setup templates reference api_key_file: / *_API_KEY_FILE env vars but config schema doesn't recognize them — silently ignored, leading to "I rotated the key" confusion [1 participants]