Files
Hermes-Skills/devops/hermes-gateway-troubleshooting/SKILL.md
T
Hermes Skills Manager 6770bc9b9d Initial commit: Hermes Agent skills collection
- Trading skills (OKX, dividend, lottery, quantitative)
- Creative skills (ASCII art, diagrams, video)
- Development skills (GitHub, debugging, TDD)
- Research skills (arXiv, blog monitoring)
- Productivity skills (email, documents, notes)
- MCP integration skills
- Custom user skills
2026-07-05 02:31:15 -04:00

176 lines
6.7 KiB
Markdown

---
name: hermes-gateway-troubleshooting
description: >
Diagnose and fix Hermes Gateway platform adapter connection issues.
Covers checking gateway state, common adapter errors (is_reconnect,
credential failures, dependency missing), safe restart procedures,
and log inspection.
trigger:
- gateway not connecting
- platform disconnected
- adapter error
- QQ收不到消息
- gateway retrying
- connect() unexpected keyword argument
- is_reconnect
- gateway state check
- 网关连不上
---
# Hermes Gateway Troubleshooting
Diagnose why a Hermes Gateway platform adapter won't connect.
## 1. Check Gateway State
The gateway state file is the single source of truth for platform connection status:
```bash
cat ~/.hermes/gateway_state.json | python3 -m json.tool
```
Look at the `platforms` dict. Each platform has:
- `state`: `"connected"` ✅, `"disconnected"`, `"retrying"`
- `error_code`: machine-readable error type or `null`
- `error_message`: human-readable error or `null`
Also check if the gateway process is alive:
```bash
ps aux | grep -i gateway | grep -v grep
systemctl --user is-active hermes-gateway
```
## 2. Categorize the Error
### Common Error Patterns
| Error message pattern | Likely cause | Fix |
|-----------------------|-------------|-----|
| `X.connect() got an unexpected keyword argument 'is_reconnect'` | Adapter `connect()` signature doesn't match base class | Add `*, is_reconnect: bool = False` to adapter's `connect()` |
| `failed to get access token` / `qq_missing_credentials` | Missing or wrong env vars/config | Check `.env` or `config.yaml` for the platform's API credentials |
| `aiohttp not installed` / `httpx not installed` | Missing Python dependency | `pip install aiohttp httpx` (or `uv pip install ...`) |
| `WebSocket closed (code=4914/4915)` | Bot offline or banned | Check bot status on platform's developer portal |
| `database is locked` (Telethon/SQLite) | Container still running with session DB | Stop container, edit DB, restart |
| `getUpdates returned 0` (Telegram) | No adapter polling / stale gateway | Kill old gateway process, restart fresh |
| `Telegram polling conflict` | Two processes sharing same bot token | `systemctl --user stop hermes-gateway`, wait 30s, `start` |
| `Connect timeout` / `Connection refused` | Outbound connectivity issue | Check proxy/VPN, firewal, or WSS_PROXY setting |
## 3. The `is_reconnect` Parameter Mismatch (Common Bug)
### Symptom
Gateway state shows the platform as `"retrying"` with error:
```
XAdapter.connect() got an unexpected keyword argument 'is_reconnect'
```
### Root Cause
The base class `BasePlatformAdapter` defines:
```python
@abstractmethod
async def connect(self, *, is_reconnect: bool = False) -> bool:
```
The gateway's reconnect watcher calls `adapter.connect(is_reconnect=True)`. If the adapter's `connect()` doesn't accept the `is_reconnect` keyword-only arg, Python throws `TypeError`.
### Fix
Add the missing parameter to the adapter's `connect()` method:
```python
# Before (broken):
async def connect(self) -> bool:
...
# After (fixed):
async def connect(self, *, is_reconnect: bool = False) -> bool:
...
```
The adapter doesn't need to *use* `is_reconnect` if it doesn't care about the distinction — just accepting the kwarg is enough to stop the TypeError. For adapters that do care (e.g., Telegram's cold boot drops the stale event queue vs reconnect preserves it), use `is_reconnect` to branch behavior.
### Verification
After fixing, restart the gateway and check state again:
```bash
systemctl --user stop hermes-gateway
sleep 30 # critical: let Telegram session expire
systemctl --user start hermes-gateway
sleep 10 # wait for startup
cat ~/.hermes/gateway_state.json | python3 -c "import sys,json; s=json.load(sys.stdin); [print(f' {k}: {v[\"state\"]}') for k,v in s['platforms'].items()]"
```
Also run the adapter's tests:
```bash
cd ~/.hermes/hermes-agent
source ./venv/bin/activate
python -m pytest tests/gateway/test_<adapter>.py -x -v --tb=short
```
### Pattern: All Adapters Must Match
Every Hermes gateway platform adapter must declare `connect()` with `*, is_reconnect: bool = False`. When adding a new adapter or updating an old one, verify this signature matches the base class.
## 4. Log Inspection
```bash
# Gateway log (general platform issues)
tail -100 ~/.hermes/logs/gateway.log | grep -iE "error|fail|disconnect|connect|retry"
# Filter by platform tag (e.g., QQBot, Telegram, Weixin)
tail -100 ~/.hermes/logs/gateway.log | grep -i "QQBot\|Telegram\|Weixin"
# Check gateway update timestamps
grep -E "state.*connected|state.*retrying" ~/.hermes/logs/gateway.log | tail -20
```
## 5. Safe Gateway Restart
**Do NOT use `hermes gateway restart`** — it kills the Telegram polling session too quickly. The new adapter starts before the old one's Telegram session expires, causing a permanent polling conflict.
### Safe Sequence
```bash
# Step 1: Stop
systemctl --user stop hermes-gateway
# Step 2: Wait for Telegram's session lock to expire (30 seconds minimum)
sleep 30
# Step 3: Start fresh
systemctl --user start hermes-gateway
# Step 4: Wait for startup
sleep 10
# Step 5: Verify
cat ~/.hermes/gateway_state.json | python3 -m json.tool
```
## 6. Platform-Specific Diagnostics
### QQ Bot
- Check `QQ_APP_ID` and `QQ_CLIENT_SECRET` in `.env`
- QQ WebSocket needs proxy env var `WSS_PROXY` or `HTTPS_PROXY` (set in `_open_ws`)
- Error 4914 = bot offline/sandbox (fatal, stop reconnecting)
- Error 4915 = bot banned (fatal, stop reconnecting)
- Verify `adapter.py`'s `connect()` accepts `is_reconnect`
### Telegram
- Only one bot token can poll at a time. Stale processes block new sessions.
- Disable bot privacy mode in @BotFather for group message reading (kick + re-add bot after changing)
- `free_response_chats` in config must be inside `telegram.extra` (NOT top-level)
### Weixin
- Requires `aiohttp` and `cryptography` packages
- Check `WX_APP_ID`, `WX_TOKEN`, `WX_AES_KEY` in `.env`
## Pitfalls
- **🔴 Gateway state file can be stale.** If `gateway_state.json` shows an old error even after restart, the new gateway process may be still starting up. Check `ps aux` for PID changes and wait.
- **🔴 sleep 30 is not optional** on Telegram restarts. Without it, the new adapter gets 409 Conflict and never connects.
- **🔴 `is_reconnect` in adapter but not in base class** — the reverse check is also worth making when adding a new adapter: if the adapter uses `is_reconnect` internally but the base class doesn't pass it (hypothetical), it'll silently default to `False` during reconnect. The gateway always passes `is_reconnect=True` on watcher-initiated reconnects.
- **Test mocks need the same signature.** If a test creates a fake adapter with `async def connect(self):` (no `is_reconnect`), it won't catch the real runtime error.