Hermes Agent is provider-agnostic: it runs on OpenRouter, Anthropic, OpenAI, Google, DeepSeek, Nous Portal, local models, and many other backends. That flexibility is its biggest strength — and the single most common source of errors. When something breaks, nine times out of ten it is the model/provider/authentication boundary: a credential expires, OAuth was never completed on the machine that actually runs the gateway, a model is renamed in the catalog, or the provider returns an error that Hermes retries and then surfaces to you.
This guide walks through the real failure modes, the exact commands to diagnose them, and the quickest fixes. It also covers a subtle Nous Portal failure that looks like a model problem even though the model configuration is correct.
The 30-second diagnostic checklist
Run these in order. Most problems become obvious within the first few commands:
hermes doctor # config + dependency health (use --fix to auto-repair)
hermes status --all # component status across the install
hermes auth list # show pooled credentials and exhaustion state
hermes config check # missing / outdated config keys
hermes portal info # crucial when model.provider is nousIf the agent itself is misbehaving rather than the provider, read the logs:
grep -i "failed to send\|error" ~/.hermes/logs/gateway.log | tail -20The files you will care about most:
| What | Location |
|---|---|
| Main config | ~/.hermes/config.yaml |
| Secrets / API keys | ~/.hermes/.env |
| Gateway + error logs | ~/.hermes/logs/ |
| Credential pools (OAuth + keys) | ~/.hermes/auth.json |
| Session store (SQLite + FTS5) | ~/.hermes/state.db |
| Skills | ~/.hermes/skills/ |
A key diagnostic principle: configuration and authentication are separate. A valid config.yaml can point at the correct provider while the credential store for that provider is empty.
Model and provider errors
These are the most frequent failures and the easiest to misread.
”Provider authentication failed” with provider: nous
A common Discord/gateway error is:
⚠️ Provider authentication failed. Check the configured credentials;
raw provider details are in the gateway logs.If your configuration looks like this:
model:
default: stealth/ox-alpha
provider: nous
base_url: https://inference-api.nousresearch.com/v1it is tempting to keep changing the model name or base_url. Do not start there. The provider can be configured correctly while the Nous Portal OAuth credential is missing.
Check the Portal state first:
hermes portal infoThe decisive failure pattern looks like this:
Nous Portal
───────────
Auth: not logged in
Model: ✓ using Nous as inference providerThat combination tells you exactly what is wrong:
Model: ✓ using Nous as inference providermeans Hermes is routing inference to Nous as intended.Auth: not logged inmeans the OAuth refresh credential is not available to the current Hermes user.- The
base_urlcan therefore be perfectly valid and requests can still fail authentication.
Fix the login:
hermes portalhermes portal is the human-friendly Nous Portal onboarding/login command. The equivalent explicit auth command is:
hermes auth add nous --type oauthFor a fresh or partially configured installation, you can run the complete Portal setup:
hermes setup --portalThen verify:
hermes portal infoYou want the summary to show:
Auth: ✓ logged in
Model: ✓ using Nous as inference providerThe Nous Portal refresh token is stored in ~/.hermes/auth.json; it is not stored in config.yaml. Hermes uses that refresh credential to mint short-lived credentials for inference calls. That separation is why editing YAML alone does not solve a missing Portal login.
Official reference: Nous Portal — Hermes Agent.
Remote Ubuntu/VPS gotcha: authenticate as the gateway user
On a VPS, Oracle Cloud instance, EC2 VM, or any remote Ubuntu host, the shell user that runs hermes portal matters. Credentials land under that user’s home directory.
For example, if you authenticate as ubuntu:
/home/ubuntu/.hermes/auth.jsonbut the gateway service runs as root or as a dedicated hermes user, that process will read a different credential store and can continue returning Provider authentication failed.
Check which user owns the running service:
ps -eo user,pid,cmd | grep -i '[h]ermes'
systemctl --user status hermes-gatewayIf the gateway runs as another account, authenticate as that account and verify hermes portal info in that same environment. The Hermes OAuth troubleshooting documentation explicitly calls out tokens landing in the wrong ~/.hermes as a remote-host failure mode.
After authentication, restart the long-running gateway so it begins from a clean state:
hermes gateway restartIf you manage Hermes with your own systemd, Docker, tmux, or supervisor setup, restart that process instead.
SSH and headless authentication
Nous Portal authentication uses OAuth. On a remote machine, follow the flow printed by Hermes and open the authorization URL in your normal browser. Current Hermes documentation also supports the Nous device-code flow for remote hosts, so hermes auth add nous --type oauth is the best first choice on an SSH-only machine.
See OAuth over SSH / Remote Hosts for the current provider-specific behavior.
Tool Gateway says “not configured” — is that the auth error?
Not necessarily. hermes portal info can also show:
Tool Gateway
────────────
Web tools not configured
Image generation not configured
Video generation not configured
OpenAI TTS not configured
Speech-to-text not configured
Browser automation not configured
Modal execution localThose lines describe optional tool routing. They do not explain a failed LLM inference request when the important line above them says Auth: not logged in. Fix Portal authentication first. Configure Tool Gateway services separately if you want managed web search, image generation, TTS, browser automation, or other extras.
”The model provider failed after retries”
This means Hermes called the LLM, the call failed, and the built-in retry/backoff loop exhausted its attempts. The raw provider error is deliberately kept out of chat output for privacy — it lands in the gateway logs instead.
Look there first:
grep -i "provider\|retry\|upstream\|timeout\|auth" ~/.hermes/logs/gateway.log | tail -40The usual causes:
- Provider authentication failure — especially
provider: nouswith Portal not logged in. - Provider outage or partial degradation — the upstream API is returning 5xx.
- Rate limiting (HTTP 429) — you are over quota. With credential pools this normally means every key in the pool is temporarily exhausted.
- Expired, revoked, or exhausted API key in the pool.
- Wrong
base_urlfor a custom endpoint. - Network or TLS issues between the gateway and the provider.
Fix it:
hermes auth list # confirm the pool looks healthy
hermes portal info # if provider is nous
hermes auth reset PROVIDER # clear an exhaustion flag on a provider
hermes auth add PROVIDER # add or refresh a credential
hermes model # switch to a different model or providerIf the error is intermittent, move to a different provider and let the pool rotate. If it is constant, inspect auth first, then the model id and base_url.
”The model provider is rate-limiting requests” (HTTP 429)
This is a rate-limit response, not a retry-exhaustion or auth failure. The provider returned HTTP 429 Too Many Requests — your request volume has exceeded the provider’s quota or rate window for the selected model/key:
⏱️ The model provider is rate-limiting requests. Please wait a moment and try again.
It is surfaced directly rather than retried silently, because retrying a 429 against the same credential only extends the block.
Diagnose it:
grep -i "429\|rate" ~/.hermes/logs/gateway.log | tail -20
hermes auth list # look for "rate-limited" or "exhausted" on a pool memberWith credential pools, this message frequently appears when every key in the pool is simultaneously rate-limited or exhausted. The usual causes:
- Burst overage — sent more requests in a short window than the provider allows.
- Exhausted pool — all pooled keys share the same rate limit and are locked out together.
- Free-tier rate caps — free models often have stricter per-window limits than paid tiers.
Fixes, in order of preference:
- Wait for the rate window to reset, then retry.
- Clear a stale exhaustion flag on the pool member:
hermes auth reset PROVIDER - Rotate to a fresh key or add one (pools rotate automatically when a member is marked exhausted):
hermes auth add PROVIDER - Switch models to one with a higher rate ceiling:
hermes model # pick a currently-listed model - Switch providers entirely for the session:
hermes model # choose a different provider
A practical rule: a single 429 is a timing signal (back off and retry later). Repeated 429s point to a credential-pool problem — add a fresh key or move providers rather than hammering the same exhausted endpoint.
Choosing a Nous Portal model without creating another failure
Run:
hermes modelWhen you choose Nous Portal, Hermes presents its current model catalog. Treat that selector as the source of truth for what your installed version can select interactively; model availability, sale pricing, and free-tier entries can change over time.
On September 10, 2026, the selector included these free models:
| Free model | Cost shown by CLI |
|---|---|
stealth/ox-alpha | free |
upstage/solar-pro4:free | free |
meituan/longcat-2.0:free | free |
tencent/hy3:free | free |
poolside/laguna-s-2.1:free | free |
stepfun/step-3.7-flash:free | free |
poolside/laguna-xs-2.1:free | free |
The same selector also exposed paid models across Anthropic, OpenAI, Google, xAI, DeepSeek, Qwen, Moonshot AI, MiniMax, Z.ai, Xiaomi, Tencent, StepFun, NVIDIA, Sakana, and others. Examples in that snapshot included anthropic/claude-sonnet-5, anthropic/claude-opus-4.8, anthropic/claude-haiku-4.5, openai/gpt-5.6-sol, openai/gpt-5.6-luna, google/gemini-3.1-pro-preview, google/gemini-3.7-flash, x-ai/grok-4.6, deepseek/deepseek-v4-pro, and qwen/qwen3.8-max.
The CLI marks promotional pricing with a star (★) and shows input, output, and cache pricing per million tokens. The September 2026 snapshot showed a wide range of per-million-token prices — from $0.05 input for deepseek/deepseek-v4-flash up to $24.00 input for openai/gpt-5.5-pro — so treat the selector as the source of truth for current commercial pricing rather than any hardcoded value. Because those prices can change, copy them from the current hermes model screen rather than hardcoding an old number into automation.
A practical troubleshooting rule for the free tier:
- Select a free model such as
stealth/ox-alpha. - Confirm
hermes portal infosaysAuth: ✓ logged in. - Smoke-test the model in the CLI.
- Only then restart or test the Discord gateway.
This separates catalog/model problems from Portal authentication problems. If the same model works in the CLI but not in Discord, focus on the gateway process, environment, Linux user, and credential path rather than changing the model again.
”HTTP 404: Model ‘X’ not found”
This means the exact model string Hermes is configured to use is not present in its internal model map or in the provider’s current catalog. Hermes looked, did not find it, and refused to send a request that would never succeed.
Common causes:
- The model was deprecated or renamed by the provider. This is especially common with rotating free-tier models.
- A typo in the model id, such as an old or malformed
:freeslug. - Provider mismatch — the model exists on one provider but
provideris set to another. - A stale per-job model override on a cron job pointing at a model that no longer exists.
Fix it:
hermes model # pick a currently-valid model interactively
hermes chat -m openrouter/<model> # smoke-test an OpenRouter model
hermes cron list # find jobs with a pinned model
hermes cron edit <job_id> # update or clear the per-job model overrideFor Nous Portal specifically, prefer selecting from the current hermes model menu before manually typing a slug. If a model disappeared from the free list, choose another currently listed entry rather than assuming yesterday’s slug is still routable.
For scheduled jobs, the model override is set at creation time and does not follow the profile default afterwards. A model that disappears from the catalog will keep 404-ing until you edit the job.
Cron failure: “This model’s free period has ended”
A cron job that targets a free-tier model can fail with a provider-specific 404 whose body reads:
⚠️ Cron ‘Daily SEO agent batch (all 11 sites)’ failed: HTTP 404: This model’s free period has ended. Please select a different model to continue!
The model slug was valid when the job was created, but the provider rotated it out of the free tier (or ended its free period) while the job kept the old pinned model. Because per-job overrides don’t follow profile defaults, the job continues pointing at the now-gone free model.
Fix it:
hermes cron list # find the failing job
hermes cron edit <job_id> # update the model, or clear the override
hermes cron edit <job_id> --model "" # clear override -> falls back to profile defaultWhen re-editing, pick from the current hermes model menu rather than re-typing an old slug, then smoke-test in the CLI before trusting it in the scheduler:
hermes model # pick a currently-listed modelA robust preventative pattern: give free-tier cron jobs a fallback chain so a rotated model rolls to a paid or alternate provider instead of hard-failing:
hermes fallback add # append a provider + model to the chain
hermes fallback list # inspect the chainThe model declined to respond (safety refusal)
This one is different from the failures above. The request reaches the model, the model runs, and then refuses to answer. Hermes does not crash — it reports the refusal straight back into the chat with a clear label:
The model declined to respond to this request (safety refusal). The model declined to respond to this request (safety refusal — not a Hermes/gateway failure). Model’s explanation:
<the model's own message>
This is not a credential, network, or gateway problem. No hermes doctor, no log crawl, no hermes auth command will fix it, because nothing on the Hermes side failed. The upstream model decided not to produce an answer for that specific prompt.
What you are actually looking at:
- The “safety refusal” label — the provider’s moderation layer (or the model’s own system guidance) stopped generation.
- “not a Hermes/gateway failure” — Hermes is telling you the breakdown is upstream, so do not burn time on infrastructure diagnostics.
- “Model’s explanation” — the text the model returned instead of an answer.
Why it happens:
- The prompt touched a policy boundary the provider enforces.
- The model’s safety classifier misfired on ambiguous phrasing, quoted text, or a mixed-language prompt.
- A free-tier model may have different moderation behavior than another model.
How to get a useful answer:
- Rephrase. Narrow the context or split the request into smaller steps.
- Switch models. Another model may classify the prompt differently:
hermes model - Add a fallback provider:
hermes fallback add hermes fallback list - For scheduled jobs, use the fallback chain so transient provider errors do not stop every run.
hermes fallback clear # remove all fallback entriesA fallback chain helps with provider-side refusals and transient errors, but it is not a guarantee. If every provider refuses the same prompt, rephrase it.
”Model returned no content after all retries” (empty response)
This is different from the two failures above. The request succeeds at the HTTP level — no thrown error, no refusal text — but the model comes back with an empty completion. Hermes retries (you will see “Empty response from model — retrying (1/3)” … “(3/3)”), and when every attempt returns nothing it surfaces:
Model returned no content after all retries. No fallback providers configured.
The second half of that message is the actionable hint: because no fallback chain was configured, an empty primary response had nowhere to roll over to.
How it differs from the other two:
- vs “provider failed after retries” — that is a thrown error or non-200 from upstream. This is a successful call that returned an empty body.
- vs “model declined to respond” — that is an explicit refusal with explanation text. This is empty: no answer and no refusal message.
Common causes:
- A free
:freemodel occasionally emits an empty completion, especially on long or edge-case inputs. - An overloaded or degraded upstream returns a 200 with empty
choices. - A local/proxy endpoint (
hermes proxy) is misconfigured and returns no body.
Fix it:
- Add a fallback provider so a future empty response rolls to the next model in the chain — exactly what the “No fallback providers configured” hint points at:
hermes fallback add # pick provider + model, appended to the chain hermes fallback list # show the current chain hermes fallback clear # remove all fallback entries - Switch the primary model. Use
hermes model, or smoke-test first:hermes chat -m openrouter/<other-model> # confirm it returns text - If you run a local/proxy endpoint, verify it returns valid completions (correct
base_url, no emptychoices), then retry.
”Credit access paused — run /topup” (subscription credits)
This is a Nous Portal billing state, not a model or credential error. When your Portal credits are exhausted or paused, inference is blocked before it reaches a model and you see:
✕ Credit access paused · run /topup to top up
Fix it:
hermes portal open # opens the subscription / top-up page in your browser
hermes portal info # confirm Portal auth + Tool Gateway routing
hermes portal status # quick billing/auth health checkhermes portal open lands on the Nous Portal subscription page. There is no hermes topup, hermes credit, or hermes subscription subcommand — the portal open command is the supported way to reach billing. After you top up, no reinstall or restart is required; the next request picks up the restored credit automatically.
Note: a credit-paused Portal can also surface through the empty-response / “No fallback providers configured” path above, because the gateway never receives a real completion. Top up first; if empty responses persist afterwards, move on to the fallback steps.
”Provider authentication failed”
This is a credential rejection from the provider (typically HTTP 401/403 at auth), distinct from “provider failed after retries,” which is about transient or 5xx errors. The message is explicit:
⚠️ Provider authentication failed. Check the configured credentials; raw provider details are in the gateway logs.
The raw provider auth error is deliberately kept out of chat for privacy — it is in the gateway logs:
grep -i "auth\|401\|403\|unauthorized" ~/.hermes/logs/gateway.log | tail -20Fix it:
hermes auth list # show pooled credentials + exhaustion state
hermes auth reset PROVIDER # clear an exhaustion/error flag
hermes auth add PROVIDER # re-add or refresh an OAuth / API-key credentialCommon causes: an expired OAuth token, a revoked or rotated API key, or the wrong key slotted into a provider. For the Copilot 403 gotcha, a gh auth login token does not work for the Copilot API — use the Copilot device-code OAuth flow via hermes model → GitHub Copilot.
Credentials and credential pools
Multiple credentials per provider form a pool that rotates automatically and skips exhausted keys. Problems here usually show up as repeated provider failures rather than a clean auth error.
hermes auth # interactive credential manager
hermes auth list [PROVIDER] # list pooled credentials + state
hermes auth reset PROVIDER # clear exhaustion status
hermes auth remove PROVIDER INDEX
hermes auth add [PROVIDER] # add or refresh a credentialFor Nous Portal, remember that the OAuth state is visible with:
hermes portal infoand the login can be refreshed with:
hermes portal
# or
hermes auth add nous --type oauthOne other gotcha: a Copilot 403. A gh auth login token does not work for the Copilot API. Authenticate through the Copilot-specific OAuth device flow: hermes model → GitHub Copilot.
Gateway (messaging platform) issues
The gateway is what connects Hermes to Discord, Telegram, Slack, WhatsApp, and more. Most gateway problems are environmental, not code.
Read the logs first:
grep -i "failed to send\|error\|auth" ~/.hermes/logs/gateway.log | tail -30Gateway works in CLI but Discord says provider authentication failed:
hermes portal info
ps -eo user,pid,cmd | grep -i '[h]ermes'If the CLI is authenticated but the gateway process belongs to a different Linux user, authenticate under the gateway account or fix the service user/home environment. This is one of the most useful checks on VPS deployments.
Gateway dies when you log out of SSH:
sudo loginctl enable-linger $USER # keep user services alive after logoutGateway dies when WSL2 closes: WSL2 needs systemd=true in /etc/wsl.conf for user services to survive. Without it the gateway falls back to nohup and dies with the session.
Crash loop:
systemctl --user reset-failed hermes-gatewayPlatform-specific:
- Discord bot is silent — enable Message Content Intent under Bot → Privileged Gateway Intents.
- Slack bot only answers DMs — subscribe to the
message.channelsevent; without it the bot ignores public channels.
Control commands: hermes gateway status, hermes gateway restart, hermes gateway setup.
Gateway shutting down mid-task:
⚠️ Gateway shutting down — Your current task will be interrupted.This is not a crash. The gateway received a stop/shutdown signal (for example a hermes gateway restart, a service-manager stop, or a host-level event such as OOM-killer, a restart of the host, or a systemd unit restart) while a request was in flight. The in-progress task is cancelled so the process can exit cleanly.
Diagnose it:
systemctl --user status hermes-gateway # was it stopped / is it restarting?
journalctl --user -u hermes-gateway --since "5 min ago" | grep -i "stop\|shutdown"
grep -i "shutting" ~/.hermes/logs/gateway.log | tail -10Fixes:
- If the gateway is simply restarting, wait for it to come back, then resend the request — long-running work is not automatically resumed; you must restart it in the new session.
- If a memory limit is killing the process, raise it:
# for a systemd user service, override the memory ceiling systemctl --user edit hermes-gateway # then add: # [Service] # MemoryMax=2G systemctl --user restart hermes-gateway - Schedule restarts during quiet windows (use
/restartorhermes gateway restart) rather than letting the OS decide, so in-flight tasks are not lost unexpectedly.
Tools and skills not available
A tool or skill you expect is missing from the running session.
hermes tools list # all toolsets and their enabled state
hermes tools enable NAME # enable a toolset (or `hermes tools` interactively)
hermes skills list # installed skills
/skill <name> # load a skill into the current session
hermes -s <name> # preload a skill at launchWhy it still does not appear: toolset and skill changes take effect on /reset (a new session). They are not applied mid-conversation, to preserve prompt caching.
Config changes not taking effect
| Change type | Action |
|---|---|
| Gateway config | /restart (slash command) |
| CLI config | exit and relaunch hermes |
| Tools / skills | /reset (new session) |
| Code changes | restart the CLI or gateway process |
| Nous OAuth login | authenticate, then restart long-running gateway if needed |
One exception worth flagging: security.redact_secrets is snapshotted at import time. Toggling it mid-session (even via an env var) will not take effect for the running process. Change it in config.yaml and start a new session.
Auxiliary models (vision, compression, session_search)
If vision analysis, context compression, or session search fail silently, the auto provider cannot find a backend. Fix it by providing a key or pinning each auxiliary task explicitly:
# give the auto-resolver a key to use
export OPENROUTER_API_KEY=... # or GOOGLE_API_KEY
# or pin a provider/model per auxiliary task
hermes config set auxiliary.vision.provider <provider>
hermes config set auxiliary.vision.model <model_name>Voice (STT / TTS)
Speech-to-text not working:
# config.yaml
stt:
enabled: true
provider: local # local | groq | openai | mistrallocal needs pip install faster-whisper (free, no key). Otherwise set the matching API key.
Text-to-speech not working: pick a provider in config — edge (free, default), elevenlabs, openai, minimax, mistral, or local neutts.
Slash commands: /voice on (voice-to-voice), /voice tts (always voice), /voice off.
Escalation and reporting
When you have isolated the problem but still need help:
- Isolate project rules from Hermes:
hermes --ignore-rulesskips all.hermes.md/AGENTS.md/CLAUDE.md/SOUL.mdinjection. If the bug disappears, it is in your project context file, not Hermes. - Upload a debug report:
/debugcollects system info plus logs and returns shareable links. - Nous Portal docs: https://hermes-agent.nousresearch.com/docs/integrations/nous-portal
- OAuth/remote-host docs: https://hermes-agent.nousresearch.com/docs/guides/oauth-over-ssh
- General docs: https://hermes-agent.nousresearch.com/docs/
Related Articles
- Connecting Hermes Agent to Discord: Bot Setup, Intents & Gateway Config — step-by-step Discord integration guide
- Connecting Hermes Agent to GitHub: Auth Setup and Gotchas — GitHub authentication and OAuth setup
- What is Hermes Agent? Nous Research’s Self-Improving AI Agent — architecture and capabilities overview
Quick reference: error to action
| Symptom | First command | Likely fix |\n| --------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------- | | Provider authentication failed + provider: nous | hermes portal info | if Auth: not logged in, run hermes portal | | Nous model configured, Discord still fails auth | check gateway Linux user | authenticate in that user’s ~/.hermes and restart gateway | | “model provider failed after retries” | hermes auth list / hermes portal info | refresh auth, rotate key, or switch model | | “The model provider is rate-limiting requests” | grep -i 429 ~/.hermes/logs/gateway.log | wait for window reset, hermes auth reset, switch models | | “Gateway shutting down — task interrupted” | systemctl --user status hermes-gateway | wait for restart, resend; raise MemoryMax if OOM | | “HTTP 404: Model ‘X’ not found” | hermes model | pick a model that exists in the current catalog | | old free model stopped working | hermes model | select a currently listed :free model; run hermes update to refresh the catalog | | cron job fails on model 404 | hermes cron edit <id> | update the per-job model override | | cron “free period has ended” | hermes cron edit <id> | update pinned model + add a fallback chain | | gateway silent on Discord | check Bot intents | enable Message Content Intent | | gateway dies after SSH logout | loginctl enable-linger | keep user service alive | | tool/skill missing | hermes tools / /skill | enable, then /reset | | config change ignored | /restart or relaunch | new session / process | | aux vision/compression broken | hermes config set auxiliary.* | set provider or key | | Copilot 403 | hermes model → GitHub Copilot | use device-code OAuth, not gh token | | “The model declined to respond” (safety refusal) | hermes fallback add | rephrase, switch model, or set a fallback chain | | “Model returned no content after all retries” | hermes fallback add | add a fallback chain, or switch/smoke-test the model | | “Credit access paused — run /topup” | hermes portal open | top up at portal.nousresearch.com; credit restores automatically | | “Provider authentication failed” | hermes auth list | refresh/re-add credential; check gateway logs for raw error |