#discord command issues

88 messages · Page 1 of 1 (latest)

raven quartz
#

when i try commands like /status or to change my model it will say something like ⚠️ Tried to set claude-sonnet-4-6, but current model is minimax-portal/MiniMax-M2.7. and will show me a tick and say done while it wasnt done

violet sluiceBOT
crystal idolBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> ✅ Mark Solution

crimson palmBOT
#

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:

  1. wait until the thread is idle
  2. run /model status
  3. retry /model <provider/model> using the full provider/model form
  4. run /status again

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

raven quartz
#

"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)

crimson palmBOT
#

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 commands
  • commands.allowFrom → who is allowed to use commands
  • session.dmScopeDM routing only, not this Discord thread
  • requireMention: 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:

  1. run /model status in the broken thread
  2. run /status right after
  3. try the same /model <provider/model> in a fresh new thread
  4. if the fresh thread works, it’s very likely a stuck thread/session binding issue, not commands.native
raven quartz
#

{
"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"
}
}
},

crimson palmBOT
#

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.primary is 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-6 is 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:

raven quartz
#

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
crimson palmBOT
#

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:

  1. the session override in this thread is stuck/not persisting
  2. this thread has a stale bound session
  3. there’s a bug in the Discord native /model flow 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 sonnet in a fresh thread
raven quartz
#

my config is long so ill send you my complete config in 2-3 parts it may be in there

crimson palmBOT
#

Yep, send it over, but please redact all secrets/tokens first.

Most relevant parts for this issue are:

  • agents.defaults
  • agents.list
  • bindings
  • session
  • channels.discord
  • channels.modelByChannel
  • models.providers

If you want to save time, those sections matter more than the rest.

raven quartz
#

{
"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"
}
}
},

crimson palmBOT
#

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.

raven quartz
#

"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
}
}
}
},

crimson palmBOT
#

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 /model flow

If there’s a third part, the most interesting thing left would be whether you have:

  • channels.modelByChannel
  • session.threadBindings
  • channels.discord.threadBindings
  • any extra bindings rules

Those are the only config areas I’d still side-eye here.

raven quartz
#

"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"
}
}

crimson palmBOT
#

Yep, I don’t see a config problem here.

You’ve now shown:

  • valid model catalog
  • valid dlab provider
  • 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:

  1. in this thread:
    /new sonnet
    
  2. if it still sticks to minimax, restart the gateway:
#
   openclaw gateway restart
  1. 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 --version
  • openclaw models status
  • the exact ⚠️ Tried to set... message
  • “reproduces in fresh thread after gateway restart”

That should give maintainers something actionable fast.

raven quartz
#

doing /new sonnet seems to work and make it sonnet however when i follow it with /status i get ✅ Done.

crimson palmBOT
#

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 /status is 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 sonnet fixes the stuck model
  • native /status only shows ✅ Done
#
  • whether hey /status works as a normal message
raven quartz
#

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

crimson palmBOT
#

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 /status slash 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 /status only returns ✅ Done
  • inline hey /status returns the correct status card
  • /new sonnet fixes the stale minimax session

That’s a pretty clean repro now.

raven quartz
#

but i had faced this same problem before and fixed it throigh you and it was something to do with the config

crimson palmBOT
#

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: {
raven quartz
#

and by doing this would /model etc work

crimson palmBOT
#

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 /model picker 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.

raven quartz
#

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

crimson palmBOT
#

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.native only controls whether Discord native slash commands are registered
  • commands.allowFrom / commands.useAccessGroups only control authorization
  • in your config, commands.allowFrom.discord includes guild:1298062872223551518, which effectively authorizes the whole guild for commands
  • and we already proved the same user can run the text/inline /status path 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 /status works
  • native slash /status gets 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.

raven quartz
#

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>"
     ]
    
    }
    },
crimson palmBOT
#

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:123456789
  • 123456789
  • @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:

  1. set:
    channels: {
      discord: {
        commands: { native: false }
      }
    }
    
  2. restart gateway
  3. set it back to auto or true
  4. 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.

raven quartz
#

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

crimson palmBOT
#

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.

raven quartz
#

/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

crimson palmBOT
#

Got it.

Then I’d assume one of these is happening:

  1. native commands are still registered, so Discord is still treating /model as a native slash command
  2. the gateway wasn’t restarted after changing commands.native
  3. you may have another bot/install in the server still owning that slash command

A quick sanity check:

  • if typing /model still opens the native slash UI, then the native command path is still active
  • if native was really disabled, /model sonnet should go through as a plain text message

So I’d do this exactly:

  1. set:
#
   channels: {
     discord: {
       commands: { native: false }
     }
   }
  1. restart:
    openclaw gateway restart
    
  2. wait a moment, then try /model sonnet again

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?
raven quartz
#

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 🤷

crimson palmBOT
#

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.

raven quartz
#

it was 2 different messages

crimson palmBOT
#

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 sonnet is being treated like ordinary chat, the text-command path probably isn’t catching it
  • commands.text is the switch for parsing /... in normal chat messages
#
  • native: false avoids the broken Discord slash-command path

So the clean test is:

  1. set commands.text: true
  2. set channels.discord.commands.native: false
  3. restart
  4. send /model sonnet as a standalone message

If that still fails, then I’d stop blaming config and call it a bug in that install/runtime.

raven quartz
#

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

crimson palmBOT
#

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 /status path is broken
  • text /model path 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.

raven quartz
#

how do i downgrade openclaw version

crimson palmBOT
#

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.

raven quartz
#

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

crimson palmBOT
#

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:

  1. Bare ID is not “required for native slash commands”
    Discord command allowlists normalize these to the same user id:

    • 123456789
    • user:123456789
    • discord:123456789

    So you do not need all three formats.

  2. useAccessGroups: false should not matter when commands.allowFrom is set
    The docs are explicit: when commands.allowFrom is 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.

raven quartz
#

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.

crimson palmBOT
#

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.discord does normalize:

    • 123456789012345678
    • user:123456789012345678
    • discord: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.

  • /model does 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.allowFrom is 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