#4.23 -> 5.20: discord breaks
1 messages Ā· Page 1 of 1 (latest)
Stop, Krill, and let me post all the info
Pinched-Nerve, first thing Iād check after that jump is whether Discord is now failing closed on guild access rather than actually being disconnected.
Please donāt paste your bot token, but can you paste the output of:
openclaw --version
openclaw status --all
openclaw channels status --probe
And if Discord is configured but not replying in server channels, run this repair/restart pass too:
openclaw doctor --fix
openclaw gateway restart
openclaw channels status --probe
The current docs say Discord guild handling defaults to groupPolicy: "allowlist" when Discord is configured/falls back from env, so old setups that only had DISCORD_BOT_TOKEN or loose guild config can look like āDiscord brokeā after upgrade. For server channels, verify you have a guild block like:
{
channels: {
discord: {
enabled: true,
groupPolicy: "allowlist",
guilds: {
"YOUR_SERVER_ID": {
requireMention: true,
users: ["YOUR_USER_ID"]
}
}
}
}
}
If the bot is online but silent: check Message Content Intent in the Discord Developer Portal, the guild/channel allowlist, and whether requireMention means it only answers when mentioned. Docs: https://docs.openclaw.ai/channels/discord and https://docs.openclaw.ai/channels/troubleshooting
Got it. Iāll pause and wait for the details.
I'm attaching my openclaw.json after doctor:
openclaw see's the config and appears to be happy with it. There are no log errors regarding discord.
However, discord isn't seeing the bot as being online.
Thanks, this is much more actionable.
First: you pasted gateway.auth.token in a public thread. It is not your Discord bot token, but it is still a bearer token for your gateway. Rotate it after this:
openclaw config set gateway.auth.token "$(openssl rand -hex 32)"
openclaw gateway restart
For the Discord breakage, the config is very narrow:
channels.discord.guilds["1012875612672753714"].channels = {
"1503873770945904671": { requireMention: false }
}
Per the Discord docs, once guilds.<guild>.channels exists, non-listed channels are denied. So in this config only channel 1503873770945904671 is allowed. Everything else in that server will look dead/ignored. Also, the guild default is requireMention: true, so channels you add later will only answer when mentioned unless you override them.
If you want the bot to work in all channels in that guild, remove the channels block entirely:
{
channels: {
discord: {
enabled: true,
groupPolicy: "allowlist",
guilds: {
"1012875612672753714": {
requireMention: true,
users: ["563134939021967380"]
}
}
}
}
}
If you only want specific channels, add each channel ID under guilds.<guild>.channels.
Your binding is also scoped to only that same one channel:
bindings: [{ agentId: "librarian", match: { channel: "discord", accountId: "default", guildId: "1012875612672753714", peer: { kind: "channel", id: "1503873770945904671" } } }]
That part is valid, but it means only that channel routes to librarian; other allowed channels route by normal defaults unless you add broader bindings.
After changing config, run:
openclaw gateway restart
openclaw channels status --probe
If it still fails, the next useful snippet is the log line around a message being ignored. Look for words like denied, allowlist, requireMention, guild, channel, or unresolved DISCORD_BOT_TOKEN. Docs: https://docs.openclaw.ai/channels/discord
(note that this worked pre-5.20)
Right, thatās consistent with a policy/identity mismatch rather than a bad config file. OpenClaw can be perfectly happy loading a config that only allows one Discord conversation.
The key thing in your posted config is that the only allowed guild channel is:
1503873770945904671
So if you test in any other channel/thread, there may be no āDiscord errorā; it is just outside the configured allowlist. Discord threads/forum posts are especially easy to mix up because the thread has its own ID, and the parent channel has another ID.
Two quick checks:
openclaw channels logs --channel discord
Then send one test message to the bot and see whether anything appears. If nothing appears at all, look at Discord-side permissions/intents: bot is in the server, can view that channel/thread, Message Content Intent is enabled, and the running gateway is using the expected DISCORD_BOT_TOKEN.
If a line appears but no reply is posted, itās almost certainly access/routing/mention behavior. Compare the logged guild/channel/thread IDs to your config. If the message is from a different channel/thread ID than 1503873770945904671, either add that ID to channels.discord.guilds["1012875612672753714"].channels or remove the channels block to allow all channels in that guild.
For a focused repro, temporarily make the guild broad and mention-gated:
channels: {
discord: {
enabled: true,
groupPolicy: "allowlist",
guilds: {
"1012875612672753714": {
requireMention: true,
users: ["563134939021967380"]
}
}
}
}
Restart, mention the bot in the failing place, then narrow the channel list back down once it answers.
That changes the branch: if Discord shows the bot offline, weāre before channel allowlists/routing. The gateway is probably not connected to Discord at all.
Your config uses an env SecretRef:
token: { source: "env", provider: "default", id: "DISCORD_BOT_TOKEN" }
So the most likely failure is the running gateway service does not have DISCORD_BOT_TOKEN in its environment. This is common after switching from an interactive shell to a managed service.
Check:
openclaw channels status --probe
openclaw status --all
openclaw logs --follow
Look specifically for unresolved token/ref, Discord startup, or gateway monitor lines. If you run OpenClaw as a service, put the token in ~/.openclaw/.env and restart:
printf 'DISCORD_BOT_TOKEN=your_bot_token_here
' >> ~/.openclaw/.env
openclaw gateway restart
openclaw channels status --probe
Donāt paste the token here. If .env already has it, verify the service actually restarted and that the token is still valid in the Discord Developer Portal. Docs call out this env/service case here: https://docs.openclaw.ai/channels/discord
Yep, that matters. It can still be an env/service issue if the 5.20 update reinstalled/restarted the gateway under a different environment, but ābot offlineā narrows it to Discord startup/transport, not message routing.
Please grab the Discord probe/status lines, because they should distinguish these cases:
openclaw channels status --probe
openclaw logs --follow
If you can, restart once while tailing logs:
openclaw gateway restart
openclaw logs --follow
Useful things to paste, with secrets redacted:
- unresolved
DISCORD_BOT_TOKEN/ SecretRef - Discord login/startup messages
401/ invalid token- Discord gateway websocket errors
- application/client lookup errors
One config-side workaround worth trying for 5.20: set the Discord application ID explicitly so startup can skip the application lookup REST call:
channels: {
discord: {
applicationId: "YOUR_DISCORD_APPLICATION_ID"
}
}
Keep the existing token config. The docs mention this for hosts blocked/rate-limited by Discordās startup application lookup: https://docs.openclaw.ai/channels/discord
Lots of responses, reading through them:
Note that the bot is showing OFFLINE within my discord server and via DM's. In other words, discord's servers aren't seeing the bot.
Understood, and sorry for the message pile-up. Iāll keep this to one path.
If the bot is offline in both DMs and the server, ignore the guild/channel config for now. Discord is not seeing an active gateway session for that bot token.
Please run just this and paste the Discord section/log lines, with secrets redacted:
openclaw channels status --probe
openclaw logs --follow
Then restart the gateway once and watch for Discord startup lines:
openclaw gateway restart
openclaw logs --follow
The likely causes at this layer are:
- the running service cannot resolve
DISCORD_BOT_TOKEN - the token was reset/invalidated in Discord Developer Portal
- Discord gateway websocket/login is failing
- 5.20 is failing during Discord startup before connecting
Since your config stores the token as { source: "env", id: "DISCORD_BOT_TOKEN" }, the highest-signal check is whether the managed gateway process has that env var. If itās a service install, put the token in ~/.openclaw/.env, restart, and check whether the bot turns online. Donāt paste the token here.
the status probe:
igor@openclaw:~$ openclaw channels status --probe
OpenClaw 2026.5.20 (e510042) ā Pairing codes exist because even bots believe in consentāand good security hygiene.
ā
ā
Gateway reachable.
- Telegram default: enabled, configured, running, connected, in:30m ago, out:30m ago, mode:polling, bot:@IgorAIAgentBot, token:env, works
Tip: status --deep adds gateway health probes to status output (requires a reachable gateway).
igor@openclaw:~$
krill it did successfully login based on logs but then it disconnected afterwards
That output contradicts the attached config. With a meaningful channels.discord block, channels status --probe should at least show Discord as configured or unavailable. It showing only Telegram means the running gateway is not seeing that Discord config, or the status command is talking to a different gateway/config than the file you attached.
Next checks:
openclaw config file
openclaw config get channels.discord
openclaw config validate
openclaw status --all
Then restart and re-probe:
openclaw gateway restart
openclaw channels status --probe
What Iām looking for:
- Does
openclaw config get channels.discordprint the same Discord block you attached? - Does
openclaw status --allshow the same config path you edited/attached? - After restart, does Discord appear in
channels status --probeat all?
If config get channels.discord is empty/missing, doctor produced or you attached a config file that is not the active one. If config get is correct but the gateway still only reports Telegram after restart, that points to a 5.20 runtime/channel discovery bug and is worth filing with the status/config outputs: https://github.com/openclaw/openclaw/issues
Krill, if you think you can figure it out, want ssh access to this machine? š
Thatās the key detail. If it logs in and then disconnects, weāre looking for the Discord gateway close code, not config parsing.
Please search the log around the disconnect for one of these lines:
openclaw logs --follow
# or, in another terminal after restart:
openclaw gateway restart
Look for:
discord gateway: Gateway websocket closed: <code>
discord gateway error: ...
discord: gateway closed with code 4014 ...
Max reconnect attempts ...
The big one is 4014: Discord accepted the bot token, then closed because a privileged gateway intent is requested but not enabled in the Discord Developer Portal. In current OpenClaw, Discord gateway startup requests MessageContent by default, plus optional GuildPresences / GuildMembers only if configured.
So if you see 4014:
- Enable Message Content Intent in the Discord Developer Portal ā Bot page
- If your config has
channels.discord.intents.presence: true, also enable Presence Intent or remove that config - If your config has
channels.discord.intents.guildMembers: true, also enable Server Members Intent or remove that config - Restart OpenClaw after changing the portal setting
If the close code is 4004, thatās auth/token. If itās 4013, thatās invalid intents. If itās 1006 / reconnect exhausted, that points more toward network/proxy/WebSocket interruption.
Docs: https://docs.openclaw.ai/channels/discord and https://docs.openclaw.ai/channels/troubleshooting
Paste just the 5-10 log lines around Gateway websocket closed / discord gateway error, with secrets redacted, and the close code should tell us which branch it is.
Tempting, but please donāt send SSH access or credentials here. I can help you debug this safely from command output.
Given the bot is offline everywhere, the next best data is just the Discord startup/probe output, redacted:
openclaw channels status --probe
openclaw logs --follow
Then in another terminal:
openclaw gateway restart
Paste the Discord-related lines around startup. Iām looking for token resolution, Discord login/websocket errors, or a startup exception before the bot connects. If the logs are noisy, search/filter for:
openclaw logs | rg -i 'discord|DISCORD_BOT_TOKEN|gateway|token|401|websocket|login|client|application'
Also: donāt paste the actual Discord bot token or gateway token. Redacted snippets are enough for this layer.
I'm only human. slow down.
Youāre right. Sorry, I got too noisy.
Iāll stop here. When youāre ready, send whatever output you have, and Iāll respond in one focused pass.
openclaw logs --follow | grep -i discord
openclaw gateway restart
no output
openclaw logs --follow | grep -i discord
openclaw gateway stop
openclaw gateway start
no output
Same if I monitor "journalctl | grep -i discord"
that makes no sense
Got it. One focused thing: grep -i discord may be filtering out the useful startup line. In current code the Discord provider startup log can look like:
[default] starting provider (@botname)
ā¦with no word discord in the line.
Please run this one command and paste the discord account line it prints:
openclaw channels status --probe
If you want to check logs too, donāt grep only for Discord. Use this broader filter:
openclaw logs --follow | grep -Ei 'starting provider|provider|gateway|channel|token|401|error|fatal|discord'
What Iām trying to distinguish now:
discord default ... configured ... stopped/disconnected= gateway loaded the account but the provider is not staying updiscord default ... probe failed= token/app REST probe problem- no
discordline at all = Discord channel/plugin/account is not being registered from config
The status line is the highest-signal next clue.
Fair. I explained that badly.
Ignore the log-filter point. The practical next step is simpler: channels status --probe tells us whether OpenClaw thinks the Discord account is registered/running/connected, independent of what the logs happen to say.
So the one thing I need is the Discord line from:
openclaw channels status --probe
No other commands for now.
openclaw channels status --probe
There is no output for discord. Only:
OpenClaw 2026.5.20 (e510042) ā I'll butter your workflow like a lobster roll: messy, delicious, effective.
ā
ā
Gateway reachable.
- Telegram default: enabled, configured, running, connected, mode:polling, bot:@IgorAIAgentBot, token:env, works
Tip: status --deep adds gateway health probes to status output (requires a reachable gateway).
Thatās the smoking gun. This is no longer a Discord token/gateway problem: OpenClawās gateway is not registering the Discord channel at all.
In 5.20 Discord is a bundled plugin channel. Your config has channels.discord, but the running gateway status only sees Telegram, so force-enable the Discord bundled plugin explicitly:
openclaw config set plugins.entries.discord.enabled true --strict-json
openclaw gateway restart
openclaw channels status --probe
After that, Iād expect a Discord default: line. If it appears but says disconnected/probe failed, then we go back to token/startup debugging. If it still does not appear, the next clue is whether plugin loading is blocking it:
openclaw plugins list --enabled | grep -i discord
igor@openclaw:~/.openclaw$ openclaw channels status --probe
OpenClaw 2026.5.20 (e510042) ā Automation with claws: minimal fuss, maximal pinch.
ā
ā
Gateway reachable.
- Discord default: enabled, configured, running, connected, bot:@Igor, token:config, intents:content=limited, works, audit ok
- Telegram default: enabled, configured, running, disconnected, mode:polling, bot:@IgorAIAgentBot, token:env, works
Tip: status --deep adds gateway health probes to status output (requires a reachable gateway).
Good, that confirms the root cause: Discord wasnāt being loaded/registered as a channel plugin after the upgrade. Now it is connected and the Discord API probe works.
Next, test one real message:
- DM the bot once, or mention it in an allowed server channel/thread.
- If it sees the message but does not reply, weāre back in allowlist /
requireMention/ binding territory. - If it replies, the fix is simply keeping
plugins.entries.discord.enabled: truein config.
Also note token:config now means Discord is using a configured token value/reference rather than the plain env fallback path. Thatās fine as long as the token is not pasted publicly.
good: DMs: work
bad: mentions in the discord server channels other than 1503873770945904671 do NOT work.
good: bot replies to all messages in channel 1503873770945904671
Perfect, that matches the remaining config exactly.
Your guild config only allows this one channel:
1503873770945904671
Once channels.discord.guilds.<serverId>.channels exists, only listed channels are allowed. That is why DMs work, that one channel works, and other server channels do not, even when mentioned.
Fix options:
// allow all channels in that guild, mention-gated by default
channels: {
discord: {
guilds: {
"1012875612672753714": {
requireMention: true,
users: ["563134939021967380"]
}
}
}
}
Or keep it narrow and add every allowed channel ID under channels.discord.guilds["1012875612672753714"].channels.
So the whole break was two layers: first Discord plugin wasnāt enabled/loaded after upgrade; after fixing that, the remaining server behavior is the channel allowlist doing what the config says.
This is a change from 4.23. However, I won't drag you through that. The root fix for the problem as initially described is running:
openclaw config set plugins.entries.discord.enabled true --strict-json
@halcyon sonnet "openclaw doctor --fix" did not perform the above. Perhaps this should be checked in the 4.xx -> 5.xx migration?
Is there a way to configure the discord server in such a way that the bot responds in ALL channels only if mentioned, and additionally responds in a specific channel (1503873770945904671) without requiring a mention?
Yes. Use a wildcard channel entry plus a specific override.
{
channels: {
discord: {
enabled: true,
groupPolicy: "allowlist",
guilds: {
"1012875612672753714": {
requireMention: true,
users: ["563134939021967380"],
channels: {
"*": {
enabled: true,
requireMention: true
},
"1503873770945904671": {
enabled: true,
requireMention: false
}
}
}
}
}
}
}
The important bit is "*": because once guilds.<guild>.channels exists, non-listed channels are denied unless the wildcard is present. Then the specific channel entry wins over the wildcard for 1503873770945904671.
Use enabled, not old allow; doctor --fix can migrate old allow entries, but Iād write the new shape directly.
@ionic oak I'm going to be marking the above as the correct answer, but rather than open a new help thread, can you tell me how I switch from the codex harness in 5.20 to the 3.14 harness?
Yep. The ā3.14 harnessā is the built-in PI harness.
Set the embedded harness back to PI:
openclaw config set agents.defaults.embeddedHarness '{"runtime":"pi","fallback":"pi"}' --strict-json
openclaw gateway restart
Then start a fresh session in Discord with /new or /reset. Harness choice is pinned per session, so changing config wonāt necessarily move an existing transcript off Codex.
One gotcha: if you set an env override, it wins over config. So make sure the gateway service does not have:
OPENCLAW_AGENT_RUNTIME=codex
If you were using the Codex harness specifically for Codex OAuth, also check your model ref. The docs split this as: Codex app-server harness uses embeddedHarness.runtime: "codex"; PI/Codex OAuth uses the normal PI harness with the Codex OAuth provider path. Docs: https://docs.openclaw.ai/plugins/codex-harness and https://docs.openclaw.ai/gateway/configuration-reference#agentsdefaultsembeddedharness
igor@openclaw:~/.openclaw$ openclaw config set agents.defaults.embeddedHarness '{"runtime":"pi","fallback":"pi"}' --strict-json
This generates an error:
Error: Config validation failed: agents.defaults.embeddedHarness: Invalid input
Yep, my command shape is bad for your build. Set the leaf key instead:
openclaw config set agents.defaults.embeddedHarness.runtime '"pi"' --strict-json
openclaw config unset agents.defaults.embeddedHarness.fallback
openclaw gateway restart
Then use /new or /reset in the Discord conversation you want to move, because harness choice is pinned per session.
If you want to confirm before restart:
openclaw config get agents.defaults.embeddedHarness
Expected shape is just:
{"runtime":"pi"}