The problem
Hermes gateway (Discord bot) on my Fedora 44 workstation kept dropping slash
commands: I’d send /reset or /model from Discord DM or by @mentioning the
bot in a channel, and often nothing happened — no error, no response.
Root cause chain
- Flaky DNS from the router. The wifi connection used the router
(
192.168.1.1) as DNS server. It intermittently failed:Cannot connect to host discord.com:443 [Temporary failure in name resolution]. - Zombie websocket windows. Each DNS failure caused Discord gateway
reconnects (
Discord Gateway WebSocket unhealthy (socket_closed)) and heartbeats falling behind (Can't keep up, shard websocket is 15.6s behind). During those windows the bot looked connected but wasn’t receiving events — slash interactions were delivered to a dead socket and vanished silently. - Sync churn on every restart. Every gateway restart re-synced ~64 slash commands to Discord’s API, which has a tiny rate-limit bucket. Repeated restarts kept hitting 429s (100–263s backoffs). Not the direct cause of dropped commands (registered commands persist), but it made restarts unreliable as a fix.
The fix (Fedora 44: systemd-resolved + NetworkManager)
Don’t edit /etc/resolv.conf (stub, managed by systemd-resolved) and don’t
touch shell startup files. Set DNS on the NetworkManager connection profile:
# Per-connection DNS override, persistent across reboots/reconnects
nmcli connection modify "TP-Link_C8B8" \
ipv4.dns "1.1.1.1 8.8.8.8" \
ipv4.ignore-auto-dns yes
# Re-activate
nmcli connection up "TP-Link_C8B8"
# Verify
resolvectl dns wlo1
resolvectl query discord.comThen stop the sync churn — the commands were already registered on Discord’s side (verify with the API using the bot token), so disable per-restart sync:
echo 'DISCORD_COMMAND_SYNC_POLICY=off' >> ~/.hermes/.env
hermes gateway restart # from a separate shell, not from inside the gatewayDebugging tips that helped
- Gateway logs:
grep -E 'unhealthy|Can't keep up|name resolution|429' ~/.hermes/logs/gateway.log - Check what commands Discord actually has registered (not what the bot
thinks):
GET /applications/<app_id>/commandswith the bot token. Plainurllibgets 403 (Cloudflare error 1010) — use aiohttp with a properDiscordBotUser-Agent. resolvectl statusshows which DNS server each link actually uses.- No global IPv6 on the wifi link (only link-local) — Discord over IPv6
fails instantly (
curl -6returns 000), so IPv4 is what matters here.