#discord command issues
88 messages · Page 1 of 1 (latest)
Let me check the actual command path for that warning so I can tell you whether this is expected behavior or a bug.
I found the exact Discord code path. The warning is real, not just cosmetic. Now I’m checking whether it’s a queued-switch case or a regression in the native picker.
Yep, that warning is real, not just cosmetic.
What’s happening is:
- Discord shows the green tick / “Done” because the slash command interaction was accepted
- then OpenClaw re-reads the actual session model
- if it still sees the old model, it shows
⚠️ Tried to set ..., but current model is ...
So the command UI succeeded, but the model switch did not persist.
Most common causes:
- the session was still busy, so the switch stayed pending
- thread/session binding mismatch
- older build, there have been a bunch of recent Discord model-picker fixes
Can you paste these first:
openclaw --version
openclaw status --all
Also, quick checks:
- wait until the thread is idle
- run
/model status - retry
/model <provider/model>using the full provider/model form - run
/statusagain
If it only breaks in this one thread, try the same thing in a fresh thread too, that helps confirm whether it’s a thread binding issue.
Docs:
https://docs.openclaw.ai/tools/slash-commands
https://docs.openclaw.ai/help/faq
"commands": {
"native": "auto",
"nativeSkills": false,
"restart": true,
"ownerDisplay": "raw",
"allowFrom": {
"discord": [
"user:980172182548254760",
"guild:1298062872223551518"
]
}
},
"session": {
"dmScope": "per-channel-peer"
},
"hooks": {
"internal": {
"enabled": true,
"entries": {
"session-memory": {
"enabled": true
}
}
}
},
"channels": {
"discord": {
"enabled": true,
"token": "REDACTED",
"groupPolicy": "open",
"streaming": {
"mode": "off"
},
"guilds": {
"1298062872223551518": {
"requireMention": false
}
does it have something to do with this
OpenClaw 2026.4.12 (1c0672b)
I’m just checking those config keys so I don’t hand-wave this.
Probably not that snippet, no.
Those keys mostly affect:
commands.native: "auto"→ registers native slash commandscommands.allowFrom→ who is allowed to use commandssession.dmScope→ DM routing only, not this Discord threadrequireMention: false→ whether replies need a mention in that guild
None of those should make /model say it changed when the session still stayed on the old model.
Since you’re on 2026.4.12, I’d look more at session/thread state in that specific thread:
- run
/model statusin the broken thread - run
/statusright after - try the same
/model <provider/model>in a fresh new thread - if the fresh thread works, it’s very likely a stuck thread/session binding issue, not
commands.native
Also, while testing, use the full provider/model form once, just to avoid alias weirdness.
If you can, paste the output of:
openclaw status --all
and the /model status output from the affected thread.
Relevant docs:
https://docs.openclaw.ai/tools/slash-commands
https://docs.openclaw.ai/concepts/models
https://docs.openclaw.ai/help/faq
{
"gateway": {
"mode": "local",
"auth": {
"mode": "token",
"token": "<REDACTED>"
},
"port": 18789,
"bind": "lan",
"tailscale": {
"mode": "off",
"resetOnExit": false
},
"controlUi": {
"allowedOrigins": [
"http://localhost:18789",
"http://127.0.0.1:18789"
],
"allowInsecureAuth": true,
"dangerouslyAllowHostHeaderOriginFallback": true,
"dangerouslyDisableDeviceAuth": true
},
"nodes": {
"denyCommands": [
"camera.snap",
"camera.clip",
"screen.record",
"contacts.add",
"calendar.add",
"reminders.add",
"sms.send",
"sms.search"
]
}
},
"agents": {
"defaults": {
"params": {
"cacheRetention": "long"
},
"model": {
"primary": "minimax-portal/MiniMax-M2.7",
"fallbacks": [
"minimax-portal/MiniMax-M2.7"
]
},
"heartbeat": {
"every": "30m",
"model": "minimax-portal/MiniMax-M2.7"
},
"models": {
"minimax-portal/MiniMax-M2.7": {
"alias": "minimax"
},
"dlab/claude-opus-4-6": {
"alias": "opus"
},
"dlab/claude-opus-4-5": {
"alias": "opus-4.5"
},
"dlab/claude-sonnet-4-6": {
"alias": "sonnet"
},
"dlab/claude-sonnet-4-5": {
"alias": "sonnet-4.5"
},
"dlab/claude-sonnet-4": {
"alias": "sonnet-4"
},
"dlab/claude-haiku-4-5": {
"alias": "haiku"
}
}
},
I think I see the suspicious part. Let me verify the model config contract before I point at the wrong thing.
This block is a lot more useful, and I think the answer is still “not directly”, but there’s one important thing in it:
agents.defaults.model.primaryis minimax-portal/MiniMax-M2.7- your Claude entries are only in
agents.defaults.models, which is the allowlist/catalog - those Claude entries use
dlab/..., which looks like a custom provider name
So the key question is:
Do you also have a real models.providers.dlab configured somewhere?
If not, then you’ve basically told OpenClaw:
- “these model IDs are allowed”
- but not “here is the provider implementation/auth for
dlab”
That can absolutely make things look weird.
So I’d check these next:
openclaw models status
openclaw models list --plain
And in the thread:
/model status
What I’d expect:
- if
dlab/claude-sonnet-4-6is missing / unauthenticated there, that’s the problem - if it looks healthy there but this thread still snaps back to minimax, then I’d suspect a stuck thread/session state
Also, your pasted gateway section is unrelated here, and agents.defaults.model.fallbacks being only minimax is fine, that just means minimax is the default fallback chain.
So my best guess right now is:
- missing or bad
dlabprovider config/auth, or - thread-specific session state if
dlablooks healthy
If you paste the output of openclaw models status, I can narrow it down fast.
Docs:
https://docs.openclaw.ai/concepts/models
https://docs.openclaw.ai/gateway/configuration-reference
Config : ~/.openclaw/openclaw.json
Agent dir : ~/.openclaw/agents/main/agent
Default : minimax-portal/MiniMax-M2.7
Fallbacks (1) : minimax-portal/MiniMax-M2.7
Image model : -
Image fallbacks (0): -
Aliases (7) : minimax -> minimax-portal/MiniMax-M2.7, opus -> dlab/claude-opus-4-6, opus-4.5 -> dlab/claude-opus-4-5, sonnet -> dlab/claude-sonnet-4-6, sonnet-4.5 -> dlab/claude-sonnet-4-5, sonnet-4 -> dlab/claude-sonnet-4, haiku -> dlab/claude-haiku-4-5
Configured models (7): minimax-portal/MiniMax-M2.7, dlab/claude-opus-4-6, dlab/claude-opus-4-5, dlab/claude-sonnet-4-6, dlab/claude-sonnet-4-5, dlab/claude-sonnet-4, dlab/claude-haiku-4-5
Auth overview
Auth store : ~/.openclaw/agents/main/agent/auth-profiles.json
Shell env : off
Providers w/ OAuth/tokens (1): minimax-portal (1)
- dlab effective=models.json:dlab_b3c...af13fafd | models.json=dlab_b3c...af13fafd | source=models.json: ~/.openclaw/agents/main/agent/models.json
- minimax-portal effective=profiles:~/.openclaw/agents/main/agent/auth-profiles.json | profiles=1 (oauth=1, token=0, api_key=0) | minimax-portal:default=OAuth
- openai effective=env:sk-proj-...urXLW2oA | env=sk-proj-...urXLW2oA | source=env: OPENAI_API_KEY
Good, that rules out the provider config. I’m checking the cleanest session-reset path before I suggest one.
Nice, that narrows it down a lot.
Your dlab provider is present, so this is not just missing provider/auth config.
That means the likely problem is now one of these:
- the session override in this thread is stuck/not persisting
- this thread has a stale bound session
- there’s a bug in the Discord native
/modelflow for this session
What I’d try next, in order:
/new sonnet
If that doesn’t work:
/reset
/model sonnet
/status
And if this thread uses bindings, also try:
/unfocus
/new sonnet
Why I’m pointing there: your config and provider lookup look valid, so the remaining failure is basically “the thread/session is staying on its stored minimax session state”.
Best diagnostic test:
- try the same
/new sonnetin a fresh thread
- if it works there, this thread’s session state is the culprit
If it still fails even in a fresh thread, then I’d call it a bug and ask you to file an issue with:
openclaw --versionopenclaw models status- the exact
⚠️ Tried to set...message
Issue tracker:
https://github.com/openclaw/openclaw/issues
Docs:
https://docs.openclaw.ai/concepts/session
https://docs.openclaw.ai/tools/slash-commands
my config is long so ill send you my complete config in 2-3 parts it may be in there
Yep, send it over, but please redact all secrets/tokens first.
Most relevant parts for this issue are:
agents.defaultsagents.listbindingssessionchannels.discordchannels.modelByChannelmodels.providers
If you want to save time, those sections matter more than the rest.
{
"gateway": {
"mode": "local",
"auth": {
"mode": "token",
"token": "<REDACTED>"
},
"port": 18789,
"bind": "lan",
"tailscale": {
"mode": "off",
"resetOnExit": false
},
"controlUi": {
"allowedOrigins": [
"http://localhost:18789",
"http://127.0.0.1:18789"
],
"allowInsecureAuth": true,
"dangerouslyAllowHostHeaderOriginFallback": true,
"dangerouslyDisableDeviceAuth": true
},
"nodes": {
"denyCommands": [
"camera.snap",
"camera.clip",
"screen.record",
"contacts.add",
"calendar.add",
"reminders.add",
"sms.send",
"sms.search"
]
}
},
"agents": {
"defaults": {
"params": {
"cacheRetention": "long"
},
"model": {
"primary": "minimax-portal/MiniMax-M2.7",
"fallbacks": [
"minimax-portal/MiniMax-M2.7"
]
},
"heartbeat": {
"every": "30m",
"model": "minimax-portal/MiniMax-M2.7"
},
"models": {
"minimax-portal/MiniMax-M2.7": {
"alias": "minimax"
},
"dlab/claude-opus-4-6": {
"alias": "opus"
},
"dlab/claude-opus-4-5": {
"alias": "opus-4.5"
},
"dlab/claude-sonnet-4-6": {
"alias": "sonnet"
},
"dlab/claude-sonnet-4-5": {
"alias": "sonnet-4.5"
},
"dlab/claude-sonnet-4": {
"alias": "sonnet-4"
},
"dlab/claude-haiku-4-5": {
"alias": "haiku"
}
}
},
Got it, keep going.
Nothing suspicious in this part yet, this still looks like the same valid model setup we already checked. The next parts are more likely to matter.
"list": [
{
"id": "main",
"tools": {
"profile": "full"
}
}
]
},
"models": {
"providers": {
"dlab": {
"baseUrl": "https://api.dlabkeys.com/v1",
"apiKey": "<REDACTED>",
"api": "anthropic-messages",
"models": [
{
"id": "claude-opus-4-6",
"name": "Claude Opus 4.6"
},
{
"id": "claude-opus-4-5",
"name": "Claude Opus 4.5"
},
{
"id": "claude-sonnet-4-6",
"name": "Claude Sonnet 4.6"
},
{
"id": "claude-sonnet-4-5",
"name": "Claude Sonnet 4.5"
},
{
"id": "claude-sonnet-4",
"name": "Claude Sonnet 4"
},
{
"id": "claude-haiku-4-5",
"name": "Claude Haiku 4.5"
}
]
},
"minimax-portal": {
"baseUrl": "https://api.minimax.io/anthropic",
"api": "anthropic-messages",
"authHeader": true,
"models": []
}
}
},
"tools": {
"profile": "coding",
"web": {
"search": {
"enabled": true,
"provider": "brave"
}
}
},
"commands": {
"native": "auto",
"nativeSkills": false,
"restart": true,
"ownerDisplay": "raw",
"allowFrom": {
"discord": [
"user:980172182548254760",
"guild:1298062872223551518"
]
}
},
"session": {
"dmScope": "per-channel-peer"
},
"hooks": {
"internal": {
"enabled": true,
"entries": {
"session-memory": {
"enabled": true
}
}
}
},
"channels": {
"discord": {
"enabled": true,
"token": "<REDACTED>",
"groupPolicy": "open",
"streaming": {
"mode": "off"
},
"guilds": {
"1298062872223551518": {
"requireMention": false
}
}
}
},
This part also looks fine.
Important bit: models.providers.dlab is configured correctly, so I don’t see a config mistake here that would force you back to minimax.
At this point the remaining likely causes are still:
- stale thread/session state
- thread binding/session routing
- an actual bug in the native
/modelflow
If there’s a third part, the most interesting thing left would be whether you have:
channels.modelByChannelsession.threadBindingschannels.discord.threadBindings- any extra
bindingsrules
Those are the only config areas I’d still side-eye here.
"plugins": {
"entries": {
"brave": {
"enabled": true,
"config": {
"webSearch": {
"apiKey": "<REDACTED>"
}
}
},
"minimax": {
"enabled": true
}
}
},
"meta": {
"lastTouchedVersion": "2026.4.12",
"lastTouchedAt": "2026-04-13T19:55:43.190Z"
},
"auth": {
"profiles": {
"minimax-portal:default": {
"provider": "minimax-portal",
"mode": "oauth"
}
}
},
"wizard": {
"lastRunAt": "2026-04-13T19:55:22.951Z",
"lastRunVersion": "2026.4.12",
"lastRunCommand": "configure",
"lastRunMode": "local"
}
}
Yep, I don’t see a config problem here.
You’ve now shown:
- valid model catalog
- valid
dlabprovider - no obvious
channels.modelByChannel - no obvious thread-binding override forcing minimax
So I’d stop hunting config. This looks much more like runtime/session state than bad config.
I’d try this next:
- in this thread:
/new sonnet - if it still sticks to minimax, restart the gateway:
openclaw gateway restart
- then test again in a fresh thread
If a fresh thread still reproduces after restart, I’d call it a real bug and file it here:
https://github.com/openclaw/openclaw/issues
Include:
openclaw --versionopenclaw models status- the exact
⚠️ Tried to set...message - “reproduces in fresh thread after gateway restart”
That should give maintainers something actionable fast.
doing /new sonnet seems to work and make it sonnet however when i follow it with /status i get ✅ Done.
Ah, nice, that’s actually super helpful.
That means the model problem was stale session state, and /new sonnet cleared it.
What’s left now is a different issue:
- native Discord
/statusis getting ACKed by Discord - but OpenClaw isn’t sending back the follow-up status payload
- so you only see
✅ Done.
So I’d treat this as a native /status command bug/path issue, not a model config issue.
Quick workaround to test:
send a normal message like:
hey /status
/status is one of the inline shortcuts, so if that works, it pretty much confirms the native slash-command path is the broken bit.
Also try:
/model status
If inline works but native slash /status only shows ✅ Done, I’d file that as a bug:
https://github.com/openclaw/openclaw/issues
Title idea:
Discord native /status only returns "Done" with no status payload
Include:
openclaw --version- that
/new sonnetfixes the stuck model - native
/statusonly shows✅ Done
- whether
hey /statusworks as a normal message
hey /status
Migi
APP
— 1:21 AM
Here's the current status:
🦞 Assistant 2026.4.12
🧠 Model: dlab/claude-sonnet-4-6
🔄 Fallback: minimax-portal/MiniMax-M2.7
🧮 Tokens: 6 in / 94 out
💵 Cost: $0.0000
🗄️ Cache: 50% hit rate
📚 Context: 22k/200k (11%)
⚙️ Thinking: off
Perfect, that confirms it.
So the situation is:
- your config is fine
- your model switch is fine after
/new sonnet - the remaining bug is specifically the native Discord
/statusslash command path - the inline shortcut path works correctly
So for now the workaround is:
- use
/new <model>if the thread gets stuck on an old model - use
hey /status(or another inline/status) instead of native slash/status
At this point I’d report it as a Discord native command bug:
https://github.com/openclaw/openclaw/issues
Suggested summary:
- native
/statusonly returns✅ Done - inline
hey /statusreturns the correct status card /new sonnetfixes the stale minimax session
That’s a pretty clean repro now.
but i had faced this same problem before and fixed it throigh you and it was something to do with the config
Ah, yep, that actually makes sense.
You may be remembering a config workaround, not the root cause.
Given what we just proved:
- native Discord
/status→ broken, only✅ Done - inline
hey /status→ works /new sonnet→ fixes the stale model state
…the config workaround is probably to disable native Discord commands so OpenClaw uses the text-command path instead.
That would be:
{
channels: {
discord: {
commands: {
native: false
}
}
}
}
Or globally:
{
commands: {
native: false
}
}
Then restart the gateway.
That would explain why “it was config” before, because it sidesteps the broken native slash-command path.
So:
- if you want a workaround now → disable native Discord commands
- if you want to keep native slash commands → leave config as-is and file the bug
Docs:
https://docs.openclaw.ai/tools/slash-commands
https://docs.openclaw.ai/gateway/configuration-reference
and by doing this would /model etc work
Yep, /model, /status, /new, etc. should still work, but as text commands, not native Discord slash UI.
So after setting:
channels: {
discord: {
commands: {
native: false
}
}
}
and restarting, you’d use things like:
/model sonnet
/status
/new sonnet
What you lose:
- Discord native slash command UI
- autocomplete
- native
/modelpicker dropdowns
What you keep:
- the commands themselves
- inline shortcuts like
hey /status
So yes, it should work, just through the text-command path instead of the native Discord command path.
i want you to look deeper, we know its a native discord issue does it lie in the bot itself or in the config maybe a setting to unlock to all users or seomthing
I’m going to trace the native Discord /status path a bit so I can tell you whether this smells like config gating or a bot-side bug.
I dug a bit deeper, and I’m pretty confident this is bot-side/native-command-path, not “you forgot to unlock a config flag”.
Why I’m saying that:
commands.nativeonly controls whether Discord native slash commands are registeredcommands.allowFrom/commands.useAccessGroupsonly control authorization- in your config,
commands.allowFrom.discordincludesguild:1298062872223551518, which effectively authorizes the whole guild for commands - and we already proved the same user can run the text/inline
/statuspath successfully
So if this were an auth/unlock problem, you’d usually get:
- “not authorized”, or
- no command behavior at all
But that’s not what’s happening.
What’s happening is narrower:
- text/inline
/statusworks - native slash
/statusgets ACKed by Discord - the native follow-up/status payload does not arrive
That points at the Discord native interaction reply/follow-up path in the bot, not a missing allowlist toggle.
So the honest answer is:
- Root cause: likely in the bot/native Discord command handling
- Config workaround: disable native Discord commands
- Not likely: some hidden “unlock all users” setting
If you want the practical fix now, use:
channels: {
discord: {
commands: {
native: false
}
}
}
then restart.
If you want the real fix, this is worth a GitHub issue, because your repro is very clean now:
- native
/status=> only✅ Done - inline
hey /status=> correct status card /new sonnet=> clears stale model state
If this helped, please right-click the solution message → Apps → ✅ Mark Solution so Answer Overflow can index it.
some say thiss fixed it
I tested the slash commands on a new installations in Docker where it seems to work fine. I didn't know where to look, so with some help I changed the following in my openclaw config:
--- openclaw.json(before)
+++ openclaw.current.json(after)
"ownerDisplay": "raw",
"allowFrom": {
"discord": [
-
"user:<my-discord-id>"
-
}"<my-discord-id>" ]
},
Let me verify that one before I bless it, because it’d be weird if user:<id> failed but bare <id> worked in the same allowlist.
I found the allowlist matcher. I’m checking whether bare numeric IDs and user:<id> are actually treated differently or just normalize to the same thing.
I checked the code, and that specific change should not be the real fix.
For Discord command allowlists, these normalize the same:
user:123456789123456789@sand timber
So changing:
"user:<id>"
to
"<id>"
should not unlock anything new.
Also, in your config you already have:
"guild:1298062872223551518"
which already authorizes the whole guild for commands anyway.
So if that diff seemed to fix it before, the likely real reason was a side effect:
- gateway restart
- native slash command re-registration
- stale runtime/session state getting cleared
And there’s actually a config-supported way to test that cleanly:
- set:
channels: { discord: { commands: { native: false } } } - restart gateway
- set it back to
autoortrue - restart again
Why this is worth trying: docs say commands.native: false clears previously registered Discord native commands on startup, so this forces a clean re-register.
So my current read is:
- No,
user:<id>vs bare<id>is probably not the real cause - Yes, a config change could still have “fixed it” indirectly by forcing a clean native-command reset
If you want, I can help you turn that into the smallest possible test plan so you can confirm it in 2 minutes.
hey! /model sonnet is a chat command, not something I can change — that's configured in your OpenClaw settings. you'd need to adjust it in the OpenClaw dashboard or config to switch models 😊 so i cant do /model sonnet if i wanna change mid chat
Ah, yep, that’s the important distinction.
/status works inline because it’s one of the inline shortcuts.
/model is not an inline shortcut. It’s a directive, so to persist a model change it has to be sent as a standalone message:
/model sonnet
not:
hey /model sonnet
So yes, if you disable native Discord commands, you should still be able to change models mid-chat, but only by sending /model sonnet on its own line/message.
Quick rule of thumb:
hey /status✅ workshey /model sonnet❌ not the right form/model sonnet✅ correct
/model sonnet
hey
what model are you
Migi
APP
— 2:21 AM
MiniMax-M2.7, same as before 👋
kerrsept — 2:22 AM
/model sonnet
so what model are you now
Migi
APP
— 2:22 AM
still MiniMax-M2.7! that /model command didn't go through — it's a config setting, not a chat command I can execute 🤷
doesnt seem to work
Got it.
Then I’d assume one of these is happening:
- native commands are still registered, so Discord is still treating
/modelas a native slash command - the gateway wasn’t restarted after changing
commands.native - you may have another bot/install in the server still owning that slash command
A quick sanity check:
- if typing
/modelstill opens the native slash UI, then the native command path is still active - if native was really disabled,
/model sonnetshould go through as a plain text message
So I’d do this exactly:
- set:
channels: {
discord: {
commands: { native: false }
}
}
- restart:
openclaw gateway restart - wait a moment, then try
/model sonnetagain
Also, for now, the reliable workaround we know works is still:
/new sonnet
If you want, paste what happens exactly when you send /model sonnet now:
- does Discord open a slash menu?
- does it send as plain text?
- do you get
✅ Done - or no reply at all?
kerrsept — 2:22 AM
/model sonnet
so what model are you now
Migi
APP
— 2:22 AM
still MiniMax-M2.7! that /model command didn't go through — it's a config setting, not a chat command I can execute 🤷
Ah, I see it now, that’s the problem.
You sent:
/model sonnet
so what model are you now
in the same message.
That does not count as a standalone /model directive, so OpenClaw treated it like a normal chat message and answered your question instead of switching models.
It has to be two separate messages:
/model sonnet
wait for the ack
so what model are you now
This bit is annoyingly picky, but it matches the command rules:
- directive-only message → persists
- command + extra text in same message → normal chat flow
So try exactly that, separated into two messages.
it was 2 different messages
Got it, thanks, then my last guess was wrong.
If it was two separate messages, then the next likely thing is:
- the text command parser is not active on that install, even though native slash is also broken
So I’d force both settings explicitly instead of relying on defaults:
{
commands: {
text: true
},
channels: {
discord: {
commands: {
native: false
}
}
}
}
Then restart:
openclaw gateway restart
Why I’m suggesting that:
- if
/model sonnetis being treated like ordinary chat, the text-command path probably isn’t catching it commands.textis the switch for parsing/...in normal chat messages
native: falseavoids the broken Discord slash-command path
So the clean test is:
- set
commands.text: true - set
channels.discord.commands.native: false - restart
- send
/model sonnetas a standalone message
If that still fails, then I’d stop blaming config and call it a bug in that install/runtime.
kerrsept — 2:32 AM
/model sonnet
hey what model are you
Migi
APP
— 2:33 AM
MiniMax-M2.7 😄
kerrsept — 2:33 AM
/model sonnet
what model are you
Migi
APP
— 2:34 AM
MiniMax-M2.7, always
Yep, this confirms the key point:
/model sonnet is being ignored as a command on that install.
If the command parser were catching it, you’d get some kind of command response, not silence followed by normal chat still on MiniMax.
So the state is basically:
- native slash
/statuspath is broken - text
/modelpath also isn’t parsing - normal chat still works
That means my next test is still the same one, but now with more confidence:
{
commands: {
text: true
},
channels: {
discord: {
commands: {
native: false
}
}
}
}
then:
openclaw gateway restart
After that, send only:
/model sonnet
If it still gets ignored after explicitly forcing text: true and restarting, then I’d call this a real bug in that install, not a config misunderstanding.
The fact that /new sonnet works but /model sonnet disappears is a pretty strong signal that command handling is the broken layer.
how do i downgrade openclaw version
Let me check the exact docs wording so I don’t give you a fake downgrade path.
If you installed it globally, easiest is:
pnpm add -g openclaw@<version>
openclaw doctor
openclaw gateway restart
Example:
pnpm add -g openclaw@2026.4.11
openclaw doctor
openclaw gateway restart
If you’re on a source checkout instead, it’s a git checkout + rebuild.
There’s also:
openclaw update --tag <version>
but for a clean rollback I’d usually just pin the exact version with pnpm.
Docs:
https://docs.openclaw.ai/install/updating
https://docs.openclaw.ai/cli/update
The Fix
Two changes in openclaw.json:
Add bare string IDs to commands.allowFrom.discord (and ownerAllowFrom):"allowFrom": {"discord": ["discord:YOUR_ID","user:YOUR_ID", "YOUR_ID" // <-- bare ID, required for native
slash commands ]}
All three formats are needed because different code paths match against different formats. Always use quoted strings, never bare
numbers — JavaScript truncates large integers.
Set useAccessGroups to false (if you don't have access groups configured):
"commands": {"useAccessGroups": false }
With useAccessGroups: true and no access groups defined, the authorization system fails closed and blocks all commands through the dispatch pipeline.
Then restart: systemctl --user restart openclaw-gateway
I’d be careful with that writeup, I don’t think it’s correct as stated.
For your case, two parts of it don’t line up with the docs/code:
-
Bare ID is not “required for native slash commands”
Discord command allowlists normalize these to the same user id:123456789user:123456789discord:123456789
So you do not need all three formats.
-
useAccessGroups: falseshould not matter whencommands.allowFromis set
The docs are explicit: whencommands.allowFromis configured, that becomes the command authorization source and the normal access-group path is ignored.
And in your config specifically, you already had:
commands: {
allowFrom: {
discord: [
"user:<your-id>",
"guild:<your-guild-id>"
]
}
}
So auth was already satisfied.
That’s why I still think the more likely “real fix” in stories like this is one of:
- restart cleared stale state
- native commands got re-registered
- session/runtime state changed
Not “native slash commands require bare IDs”.
So if that recipe helped someone, fine, but I would not treat it as the root cause here.
Docs:
https://docs.openclaw.ai/tools/slash-commands
If this fixed it for you, please right-click the solution message → Apps → ✅ Mark Solution so Answer Overflow can index it.
The Problem OpenClaw's commands.allowFrom.discord list had Discord user IDs only in prefixed formats:
"discord:123456789012345678",
"user:123456789012345678"
Plus precision-truncated numeric IDs (JavaScript loses precision on large integers in JSON):
123456789012345600 // last digits wrong due to floating-point
When a native Discord slash command (from the / autocomplete menu) is processed, the authorization system compares the sender's bare ID ("123456789012345678") against this list using exact string matching. None of the entries match:
"123456789012345678" !== "discord:123456789012345678" (prefixed)
"123456789012345678" !== "user:123456789012345678" (prefixed) - "123456789012345678" !== "123456789012345600" (truncated)
So isAuthorizedSender was always false. When commands like /status or /new are unauthorized, the handler silently ignores them — no reply, no error. You just see Discord's "thinking..." and then nothing.
Why /model still worked
/model has a special handler that fires before the authorization
check and directly shows an interactive picker. It never goes
through the normal command dispatch.
Why / status (with space) worked
The space prevents Discord from treating it as a native slash command. It's sent as a regular text message, which uses a
different code path where channel-level authorization (guild membership, mention detection) determines access — bypassing the
commands.allowFrom string matching entirely.
There’s one real warning in that writeup, but most of the theory doesn’t match the current code.
The one part that is real
Yes, Discord IDs should be stored as strings, not bare JSON numbers.
Large numeric IDs can get mangled if someone writes:
123456789012345678
instead of:
"123456789012345678"
So that part is valid.
The parts that don’t line up
From the current Discord native-command code:
-
commands.allowFrom.discorddoes normalize:123456789012345678user:123456789012345678discord:123456789012345678
Those are not treated as three different user ids.
-
Native slash commands do not compare only against raw bare ids with exact string matching.
-
/modeldoes not bypass authorization first. The native command auth happens before the picker path. -
Unauthorized native slash commands are not supposed to “silently ignore” like that, they should hit the unauthorized path.
-
And when
commands.allowFromis configured, the docs say that becomes the command auth source, so the text path is not just bypassing it.
So I would not trust that explanation as the root cause.
My read
The most likely real causes are still:
- stale runtime/session state
- native command registration weirdness
- an install-specific bug in the Discord native command path
If someone changed config and it “fixed” it, the meaningful part may have been:
- removing a bad numeric ID
- restarting the gateway
- forcing native command re-registration
So:
- keep ids as quoted strings ✅
- but don’t assume bare IDs are required for native slash commands ❌