ZhuLinsen/daily_stock_analysis · error · ValueError
Hermes only supports PROTOCOL=openai
Error message
Hermes only supports PROTOCOL=openai
What it means
Hermes LLM gateway config guard (src/llm/hermes.py): canonicalize_hermes_protocol normalizes PROTOCOL (strip+lower, defaulting HERMES_DEFAULT_PROTOCOL='openai') and requires exactly 'openai'. The Hermes bridge only implements the OpenAI-compatible wire protocol; any other value (anthropic, gemini, etc.) is a misconfiguration and fails fast.
Source
Thrown at src/llm/hermes.py:155
for secret in sorted(values, key=len, reverse=True):
if secret:
sanitized = sanitized.replace(secret, "[REDACTED]")
patterns = [
(r"(?i)(authorization\s*[:=]\s*)(bearer\s+)?([^\s,;]+)", r"\1[REDACTED]"),
(r"(?i)(api[_-]?key\s*[:=]\s*)([^\s,;]+)", r"\1[REDACTED]"),
(r"(?i)(cookie\s*[:=]\s*)([^\s,;]+)", r"\1[REDACTED]"),
(r"(?i)bearer\s+[a-z0-9._\-]+", "Bearer [REDACTED]"),
(r"(?i)sk-[a-z0-9_\-]+", "[REDACTED]"),
]
for pattern, replacement in patterns:
sanitized = re.sub(pattern, replacement, sanitized)
return " ".join(sanitized.split())[:300]
def canonicalize_hermes_protocol(protocol: str) -> str:
normalized = (protocol or HERMES_DEFAULT_PROTOCOL).strip().lower() or HERMES_DEFAULT_PROTOCOL
if normalized != HERMES_DEFAULT_PROTOCOL:
raise ValueError("Hermes only supports PROTOCOL=openai")
return HERMES_DEFAULT_PROTOCOL
def canonicalize_hermes_base_url(base_url: str) -> str:
"""Return canonical Hermes base URL or raise ValueError.
Allowed forms are loopback HTTP(S) URLs whose path is exactly /v1 or /v1/.
localhost is canonicalized to 127.0.0.1 to avoid DNS/hosts ambiguity.
"""
raw = (base_url or HERMES_DEFAULT_BASE_URL).strip() or HERMES_DEFAULT_BASE_URL
parsed = urlparse(raw)
if parsed.scheme.lower() not in {"http", "https"}:
raise ValueError("Hermes BASE_URL must use http or https")
if not parsed.netloc or not parsed.hostname:
raise ValueError("Hermes BASE_URL must include a loopback host")
if parsed.username or parsed.password:
raise ValueError("Hermes BASE_URL must not include userinfo")View on GitHub (pinned to 5159bd72e8)
Solutions
- Set PROTOCOL=openai (or omit it — 'openai' is the default when empty).
- Route non-OpenAI-protocol providers through the regular LLM channel config, not the Hermes bridge.
Example fix
# before PROTOCOL=anthropic # after PROTOCOL=openai
Defensive patterns
Strategy: validation
Validate before calling
from src.llm.hermes import canonicalize_hermes_protocol canonicalize_hermes_protocol(protocol) # raises on anything non-openai
Type guard
def is_openai_protocol(value: str) -> bool:
return (value or "openai").strip().lower() in {"", "openai"} Try / catch
try:
proto = canonicalize_hermes_protocol(cfg_protocol)
except ValueError:
proto = "openai" # or fail config load Prevention
- Omit PROTOCOL for Hermes (defaults to openai)
- Do not reuse multi-provider channel templates for the Hermes section
When it happens
Trigger: Setting PROTOCOL to anything other than 'openai' (case-insensitive) in Hermes-related config — 'anthropic', 'openai-compatible', 'OpenAI ' trailing space is fine (normalized) but 'oai' is not. Raised during Hermes settings canonicalization at startup.
Common situations: Copy-pasting a multi-provider LLM config template into the Hermes section; assuming Hermes proxies arbitrary protocols like the main LiteLLM channels do.
Related errors
- Responses API surface requires a normalized openai/<model> r
- LLM route aliases cannot mix API surfaces: {sorted(surface_c
- Hermes BASE_URL must use http or https
- Hermes BASE_URL must include a loopback host
- Hermes BASE_URL must not include userinfo
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/3f4f857c56f573bd.
Report an issue: GitHub.