#outh codex
1 messages ¡ Page 1 of 1 (latest)
Let me verify the auth/model docs so I can give the clean fix, not a guess.
Youâve got an auth/model mismatch.
openai/* needs a real OPENAI_API_KEY.
Codex OAuth only works with openai-codex/* (or codex/* if youâre using the Codex harness).
So the fix is one of these:
-
Using Codex OAuth
Set your model to:agents: { defaults: { model: { primary: "openai-codex/gpt-5.4" } } } -
Using direct OpenAI API
Keepopenai/gpt-5.4, but set:
export OPENAI_API_KEY=...
Docs:
- https://docs.openclaw.ai/concepts/model-providers
- https://docs.openclaw.ai/providers/openai
- https://docs.openclaw.ai/plugins/codex-harness
Also, please paste:
openclaw --version
openclaw models status
If this is a new agent, auth is per-agent, so the new agent may not have any auth profiles yet.
why do i have to grantaccces to c=edit config from UI every time can you give access to it by default
It should not ask every time.
Whatâs happening is usually one of these:
-
Your browser/device identity changes
Incognito, cleared site data, different browser/profile, or a different URL can look like a new device. -
c=edit configis an admin-scope action
config.*methods are gated asoperator.admin, so if the browser only has a lower/stale device token, the UI will trigger another approval/scope-upgrade request.
What to do:
openclaw --version
openclaw devices list
Then:
- find the pending/current browser request
- approve it with the current
requestId:
openclaw devices approve <requestId>
If it keeps happening for the same browser profile, cleanest reset is:
openclaw devices list
openclaw devices remove <deviceId>
Then reconnect the UI and approve the fresh request once.
A couple important notes:
127.0.0.1/localhostshould auto-approve- Tailnet/LAN requires explicit approval once
- same browser profile matters, clearing storage or using private mode will re-pair
I would not recommend making it globally trusted with gateway.controlUi.dangerouslyDisableDeviceAuth=true unless this is just a break-glass local box. That disables an important safety check.
Docs:
If you want, send:
openclaw --version- whether youâre connecting via localhost or Tailnet/LAN
- whether this is the same browser profile every time
and Iâll narrow down which of the two cases youâre hitting.
asking me approval every time
Yeah, if itâs asking every single time, thatâs not normal.
Most likely causes:
- using incognito/private mode
- browser is clearing site data/local storage
- switching browser/profile
- switching between
localhost/127.0.0.1/ Tailnet IP / LAN URL
Control UI treats that as a different device/browser identity.
Try this:
- use one normal browser profile, not private mode
- always open the same URL, ideally local:
http://127.0.0.1:18789/
- if itâs stuck with a bad/stale pairing, reset it once:
openclaw devices list
openclaw devices remove <deviceId>
then reconnect and approve the fresh request once
If youâre on localhost/127.0.0.1, it should usually auto-approve.
If youâre on Tailnet/LAN, one-time approval is expected, but not every time.
Send these if you want me to pinpoint it:
openclaw --version
openclaw devices list
and tell me whether youâre opening it via localhost or Tailnet/LAN.
aksing me eveyt time it ahs to exec
Ah, got it, this is exec approvals, not the config editor.
If it prompts on every exec, the effective exec policy is probably:
ask: "always", or- youâre hitting
strictInlineEvalcommands likepython -c/node -e
Easiest fix in the UI
Go to:
Control UI â Nodes â Exec approvals
Then for Gateway (or your Node, if exec runs there), change the defaults to either:
- recommended:
security=allowlist,ask=on-miss - never prompt / YOLO:
security=full,ask=off
CLI, if you want to verify first
openclaw approvals get --gateway
openclaw exec-policy show
Local ânever promptâ setup
openclaw exec-policy set --host gateway --security full --ask off --ask-fallback full
If your execs run on a node, you need to change that nodeâs approvals too, not just the gateway:
openclaw approvals get --node <id|name>
Docs:
If you want, paste openclaw approvals get --gateway and Iâll tell you the exact knob causing the repeated prompt.
ask = always
Yep, thatâs the reason.
ask=always means prompt on every exec, even if the command is already allowlisted.
If you want fewer prompts, change it to:
ask=on-missâ only prompt for commands not on the allowlistask=offâ never prompt
Good default
openclaw exec-policy set --host gateway --security allowlist --ask on-miss --ask-fallback deny
Never prompt
openclaw exec-policy set --host gateway --security full --ask off --ask-fallback full
If your execs are running on a node instead of the gateway, change that nodeâs exec approvals in:
Control UI â Nodes â Exec approvals
Docs: https://docs.openclaw.ai/tools/exec-approvals
Glad we found it đ
/approve a7de4f90 allow-once
If that short one doesnât work:
/approve a7de4f90-69db-4d31-8849-f55804ffd525 allow-once
Thatâs the current live approval for fixing the config and restarting OpenClaw.
still askign
Yep, thatâs expected.
allow-once only approves that one exec.
And with effective ask=always, it will keep prompting on the next exec anyway.
Also important: even allow-always wonât stop prompts while ask=always is active.
So the real fix is to change the policy, not keep approving commands one by one:
Prompt only on new/unallowlisted commands
openclaw exec-policy set --host gateway --security allowlist --ask on-miss --ask-fallback deny
Never prompt
openclaw exec-policy set --host gateway --security full --ask off --ask-fallback full
Then verify:
openclaw exec-policy show
openclaw approvals get --gateway
If it still says ask=always after that, the host approvals layer is still stricter than your session/config.
If your exec is running on a node, you need to change the node approvals instead of the gateway one.
discord bot invted syas integraitno require code grant
Thatâs a Discord app setting, not an OpenClaw bug.
If youâre just inviting the bot normally, go to:
Discord Developer Portal â Your App â Bot â Authorization Flow
and turn off:
- Requires OAuth2 Code Grant
Then save, regenerate/reuse the invite, and invite again.
For a normal bot invite, the OAuth2 URL should usually just include scopes like:
botapplications.commands
If Requires OAuth2 Code Grant is on, Discord expects a full OAuth2 auth-code flow instead of a normal bot invite.
So, short version: disable that toggle and re-invite.
disabled the toggle still same issue
Then itâs probably using a stale/custom invite URL, not the new setting.
Try this exactly:
- Discord Developer Portal â OAuth2
- Use the OAuth2 URL Generator, do not reuse the old link
- Select only:
botapplications.commands
- Pick the normal bot perms you need, for example:
- View Channels
- Send Messages
- Read Message History
- Embed Links
- Attach Files
- Copy the new generated URL and open that one
Important:
- avoid extra OAuth scopes like
identify,email,guilds.join - avoid any custom URL with
response_type=code/redirect_uri - avoid
Administratorunless you really need it
Thatâs the OpenClaw docs flow too: https://docs.openclaw.ai/channels/discord
If it still throws the same error after generating a fresh URL from the portal, paste the invite URL here and Iâll sanity-check it.
Because in this session I only have local filesystem, shell, web, and OpenClaw session tools, not a first-class Discord API write tool.
So I can:
configure OpenClaw locally
restart and verify the gateway
generate invite links
inspect logs
But I cannot natively do:
create Discord channels
change server settings
manage roles/permissions via Discord API
I could only do Discord-side writes if:
OpenClaw exposed a Discord messaging/admin tool here, or
I used an external script/API path with your approval and credentials
Short version, I can control your OpenClaw box directly, but not your Discord server as an admin client from this toolset.
Yeah, you can ignore that message, itâs just the failed agent talking about its own tool limits. Not the root problem.
For your issue, we donât need Discord admin API access anyway. We just need to verify the invite URL/settings.
Most useful next step:
- paste the fresh invite URL you generated from OAuth2 URL Generator
- or send a screenshot of:
- Bot tab, showing Requires OAuth2 Code Grant = off
- OAuth2 URL Generator scopes
What Iâm looking for is whether the URL still contains stuff like:
response_type=coderedirect_uri=...- extra scopes like
identify,email,guilds.join
For a normal OpenClaw Discord bot invite, it should basically just be:
scope=bot applications.commands
plus permissions.
If you paste the link, Iâll check it fast.
I can help with that, but I canât create Discord channels from here unless Uday has wired up a Discord admin skill/tool for it.
If you want, tell me:
channel name
text or voice
category
who should have access
and Iâll draft the exact setup or a clean request for Uday/admin.|
i want the capability to doit
In your own server, yes, you can wire that up, but it needs two things:
-
Discord bot permissions
Give the bot a role with at least:- Manage Channels
- optionally Manage Roles / Manage Webhooks if you want broader admin actions
-
OpenClaw tool access
The agent needs the Discord/message admin surface enabled, and you should restrict who can trigger it with your usual allowlists (channels.discord.allowFrom, command allowlists, etc.).
So the short version is:
- Discord decides what the bot account is allowed to do
- OpenClaw decides whether the agent is allowed to call those actions
Iâd only enable this on a private server you control, not a public/shared one.
If you want, I can help you set it up safely for your own Discord server and give you the minimal permission/config checklist.
its my private discord
Perfect, then this is a reasonable setup.
For a private Discord, Iâd do it like this:
1) Give the bot the Discord perms it needs
At minimum:
- Manage Channels
- View Channels
- Send Messages
- Read Message History
Optional, depending on what you want:
- Manage Threads
- Manage Webhooks
- Manage Roles (only if you really want role changes too)
2) Put your server on the guild allowlist
{
channels: {
discord: {
groupPolicy: "allowlist",
guilds: {
YOUR_SERVER_ID: {
requireMention: false,
users: ["YOUR_USER_ID"],
},
},
},
},
}
Thatâs the recommended private-server pattern from the Discord docs:
https://docs.openclaw.ai/channels/discord
3) Keep commands/tool access restricted to you
If you use command allowlists, make sure your Discord user is authorized.
4) If you run restrictive tool allowlists
Make sure the agent still has messaging enabled:
{
tools: {
allow: ["group:messaging"]
}
}
Only do that if youâre already using a restrictive tools.allow.
5) If you want config writes from chat too
{
commands: {
config: true
}
}
That enables /config ... commands, but keep access tight.
If you want, I can give you a minimal full openclaw.json snippet for a private Discord where the bot can act across the server and create/manage channels safely.
How ro make sure this bor is not added to pther servers
Two layers, do both:
1) Discord side, prevent invites
In Discord Developer Portal â Bot, turn off:
- Public Bot
That makes it so random people canât invite it to other servers.
2) OpenClaw side, ignore any other servers anyway
Keep Discord in guild allowlist mode and only list your server:
{
channels: {
discord: {
groupPolicy: "allowlist",
guilds: {
YOUR_SERVER_ID: {
requireMention: false,
users: ["YOUR_USER_ID"],
},
},
},
},
}
So even if it somehow lands in another server, OpenClaw wonât act there.
Best practice is:
- Public Bot = off
- guild allowlist = only your server
Thatâs the safe combo.
Restarted LaunchAgent: gui/501/ai.openclaw.gateway
Timed out after 60s waiting for gateway port 18789 to become healthy.
Gateway process is running but port 18789 is still free (startup hang/crash loop or very slow VM startup).
Service runtime: status=running, state=active, pid=92836
Gateway port 18789 status: free.
Gateway restart timed out after 60s waiting for health checks.
Tip: openclaw gateway status --deep
Tip: openclaw doctor
chotumiya@chotus-Mac-mini ~ % openclaw gateway restart
That message means the LaunchAgent restarted, but the gateway never actually bound port 18789. So itâs usually one of:
- invalid/broken config
- startup crash loop
- stale LaunchAgent install/path mismatch
First, please run these and paste the output:
openclaw --version
openclaw gateway status --deep
openclaw doctor
Then grab the actual startup error:
openclaw logs --follow
If status --deep or doctor suggests the service install is stale, re-write the LaunchAgent and retry:
openclaw gateway install --force
openclaw gateway restart
On macOS, this often turns out to be a stale LaunchAgent path after changing Node/global installs, so the --version + status --deep output matters a lot here.
Docs:
Paste those outputs and Iâll help narrow it down fast.
Nice, weâve got the actual root cause now:
The gateway is failing because DISCORD_BOT_TOKEN is missing for the LaunchAgent.
On macOS, launchd usually does not inherit your shell export vars, so this happens a lot.
Fix
Put the token in the gatewayâs global env file:
mkdir -p ~/.openclaw
nano ~/.openclaw/.env
Add:
DISCORD_BOT_TOKEN=YOUR_REAL_BOT_TOKEN
Save, then restart:
openclaw gateway restart
If you havenât pointed config at that env var yet
openclaw config set channels.discord.token --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN
openclaw config set channels.discord.enabled true --strict-json
openclaw gateway restart
Why this happened
Your config is using a SecretRef for channels.discord.token, but at startup the daemon canât resolve it, because the env var is missing in the service environment.
So the short version is:
- shell
export DISCORD_BOT_TOKEN=...is not enough for LaunchAgent ~/.openclaw/.envis the right place
Docs:
Also, donât paste the bot token in Discord. If you already exposed it anywhere public, rotate it first.
should add all future ekys give me a tempalte of instructions
Yep, thatâs a good default rule.
For a daemon / LaunchAgent install, future API keys and bot tokens should usually go in:
~/.openclaw/.env
Reusable template
1) Put the secret in ~/.openclaw/.env
mkdir -p ~/.openclaw
nano ~/.openclaw/.env
Add lines like:
DISCORD_BOT_TOKEN=...
OPENAI_API_KEY=...
ANTHROPIC_API_KEY=...
GOOGLE_API_KEY=...
OPENROUTER_API_KEY=...
Rules:
- one key per line
- no
export - no spaces around
= - do not paste secrets into Discord
2) Point config at the env var when needed
Pattern:
openclaw config set <config.path> --ref-provider default --ref-source env --ref-id <ENV_VAR_NAME>
Example:
openclaw config set channels.discord.token --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN
3) Restart the gateway
openclaw gateway restart
4) Verify
openclaw status
openclaw gateway status
Short instruction template you can reuse
If OpenClaw runs as a daemon/LaunchAgent, put new API keys and bot tokens in
~/.openclaw/.env, then reference them from config with an env SecretRef, then restart the gateway. Shellexport ...alone is not reliable for launchd/systemd services.
Docs: https://docs.openclaw.ai/help/environment
Glad you caught this one, itâs a super common macOS gotcha.
Not directly, no.
I can help you define it fast though, just send:
name
text or voice
category
private or public
and Iâll turn that into the exact request.
why cant it setup channels
Because setting up channels is a Discord admin action, not just normal chat.
So there are a few gates that all have to be true:
-
Discord bot permission
- the bot needs Manage Channels in your server
-
OpenClaw runtime capability
- the agent/session needs the Discord message/admin action surface exposed
- some sessions only have normal chat/send tools, not guild-admin actions
-
Your policy/authorization
- the sender still has to be allowed to trigger those actions
So when it says it âcanât set up channelsâ, it usually means one of those layers is missing, not that Discord itself can never do it.
In your case, the pasted message sounds like that specific agent session didnât have the Discord admin tool surface wired in, so it could chat but not mutate the server.
If you want, I can give you a checklist to make your private Discord bot capable of creating channels, end to end.
yes
Cool. Hereâs the end-to-end checklist to make your private Discord bot able to create channels.
1) Discord app settings
In Discord Developer Portal:
-
Bot
- Public Bot = off
- Requires OAuth2 Code Grant = off
-
OAuth2 URL Generator
- scopes:
botapplications.commands
- scopes:
-
Give the bot these permissions:
- Manage Channels
- View Channels
- Send Messages
- Read Message History
Optional:
- Manage Threads
- Manage Webhooks
- Manage Roles (only if you want role changes too)
2) Put the bot token where the daemon can read it
For a LaunchAgent / daemon install:
mkdir -p ~/.openclaw
nano ~/.openclaw/.env
Add:
DISCORD_BOT_TOKEN=YOUR_TOKEN
Then point config at it:
openclaw config set channels.discord.token --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN
openclaw config set channels.discord.enabled true --strict-json
openclaw gateway restart
3) Allow your private server + your user
Use the guild allowlist pattern:
{
channels: {
discord: {
enabled: true,
groupPolicy: "allowlist",
guilds: {
YOUR_SERVER_ID: {
requireMention: false,
users: ["YOUR_USER_ID"],
},
},
},
},
}
That makes it active in your server only.
4) Make sure messaging tools are not blocked
Only if you use restrictive tool allowlists:
{
tools: {
allow: ["group:messaging"]
}
}
If you are not using tools.allow, you can usually skip this.
5) Test it
Ask the bot something simple like:
create a text channel named
test-labunder categoryAI
If it still canât do it, check:
openclaw status
openclaw channels status --probe
openclaw logs --follow
6) Common reasons it still fails
Usually one of these:
- bot missing Manage Channels
- token not visible to the daemon
- server/user not on the allowlist
- tool policy blocks messaging/admin actions
- the specific session/runtime doesnât expose Discord admin actions
If you want, I can turn this into a single minimal openclaw.json example for your private Discord setup.
already done all these bot has admin permissions
Then Discord permissions are not the blocker. Good, that narrows it down.
At that point, itâs usually an OpenClaw tool-policy / session-capability issue:
Check 1, does this session even have the Discord message tool?
In the chat/session where you want it to create channels, run:
/tools verbose
If you donât see message, thatâs the problem.
Check 2, are you using a restrictive tool allowlist?
If you have tools.allow or per-agent tools.allow, make sure it includes:
{
tools: {
allow: ["group:messaging"]
}
}
or explicitly message.
Check 3, is this a special agent/runtime?
Some sessions can chat normally but still not expose the full Discord admin action surface.
Check 4, confirm with logs
While asking it to create a channel, run:
openclaw logs --follow
If it tries and gets blocked, the logs usually show whether it was:
- tool denied
- allowlist/policy blocked
- missing action/capability in that runtime
If you want, paste:
/tools verboseopenclaw config get toolsopenclaw config get agents.list
and Iâll tell you exactly which layer is blocking it.
{
"profile": "coding",
"deny": [
"group:automation",
"sessions_spawn",
"sessions_send"
],
"web": {
"search": {
"enabled": true,
"provider": "brave"
}
},
"elevated": {
"enabled": false
},
"exec": {
"host": "gateway",
"security": "full",
"ask": "off",
"pathPrepend": [
"/Users/chotumiya/.local/bin"
]
},
"fs": {
"workspaceOnly": true
}
Yep, there it is.
Your tool profile is coding, and coding does not include group:messaging.
That means the agent can do file/shell/web stuff, but it cannot call the message tool, which is where Discord channel actions live.
Fix
Add group:messaging to the same tools block.
If this is the block you pasted, make it:
{
"profile": "coding",
"allow": ["group:messaging"],
"deny": [
"group:automation",
"sessions_spawn",
"sessions_send"
],
"web": {
"search": {
"enabled": true,
"provider": "brave"
}
},
"elevated": {
"enabled": false
},
"exec": {
"host": "gateway",
"security": "full",
"ask": "off",
"pathPrepend": [
"/Users/chotumiya/.local/bin"
]
},
"fs": {
"workspaceOnly": true
}
}
Then restart:
openclaw gateway restart
Why
codingprofile includes fs/runtime/web/sessions/memorymessagelives undergroup:messaging- no
group:messaging= no Discord admin/message actions
So yeah, this one is tool policy, not Discord permissions. Nice catch.
Eureka); awaiting gateway readiness
06:48:21+00:00 error Cannot access rawData on partial Channel. Use fetch() to populate data.
06:48:21+00:00 error Error: Cannot access rawData on partial Channel. Use fetch() to populate data.
at GuildTextChannel.get rawData [as rawData] (file:///Users/chotumiya/openclaw/dist/extensions/discord/node_modules/@buape/carbon/dist/src/abstracts/BaseChannel.js:37:19)
at GuildTextChannel.get name [as name] (file:///Users/chotumiya/openclaw/dist/extensions/discord/node_modules/@buape/carbon/dist/src/abstracts/BaseGuildChannel.js:11:19)
at dispatchDiscordCommandInteraction (file:///Users/chotumiya/openclaw/dist/extensions/discord/provider-D8OJvlaj.js:2409:61)
at Command.run (file:///Users/chotumiya/openclaw/dist/extensions/discord/provider-D8OJvlaj.js:2366:10)
at processTicksAndRejections (node:internal/process/task_queues:104:5)
at CommandHandler.handleCommandInteraction (file:///Users/chotumiya/openclaw/dist/extensions/discord/node_modules/@buape/carbon/dist/src/internals/CommandHandler.js:119:28)
at Client.handleInteraction (file:///Users/chotumiya/openclaw/dist/extensions/discord/node_modules/@buape/carbon/dist/src/classes/Client.js:303:17)
at InteractionEventListener.handle (file:///Users/chotumiya/openclaw/dist/extensions/discord/node_modules/@buape/carbon/dist/src/plugins/gateway/InteractionEventListener.js:6:9)
at EventQueue.processListener (file:///Users/chotumiya/openclaw/dist/extensions/discord/node_modules/@buape/carbon/dist/src/internals/EventQueue.js:237:13)
at runNext (file:///Users/chotumiya/openclaw/dist/extensions/discord/node_modules/@buape/carbon/dist/src/internals/EventQueue.js:211:17)
Log tail truncated (increase --max-bytes).
Ah, this is a real bug, and itâs not a Discord permission issue.
The failure is in the Discord native slash-command path:
- OpenClaw gets a partial Channel
- then tries to read
channel.name - Carbon throws:
Cannot access rawData on partial Channel. Use fetch() to populate data.
So the current problem is basically:
native Discord command handler bug on partial channels
Good workaround right now
Disable native Discord commands and use text commands / normal chat instead.
Set:
{
commands: {
text: true
},
channels: {
discord: {
commands: {
native: false
}
}
}
}
Then restart:
openclaw gateway restart
After that, use plain chat or text /... commands instead of Discord native slash commands.
Why this helps
This avoids the buggy native interaction handler (dispatchDiscordCommandInteraction) thatâs choking on the partial channel object.
Next step
Please also send:
openclaw --version
and file this as a GitHub issue with that stack trace, because this one really does need a code fix:
https://github.com/openclaw/openclaw/issues
If you want, I can help you turn that into a clean bug report in one message.
but still the bot cant creats cahnnels
Then Iâd check one last very specific thing:
Make sure the Discord channel admin action gate is on
channel-create is controlled by:
channels.discord.actions.channels
Set it explicitly to avoid guessing:
{
channels: {
discord: {
actions: {
channels: true
}
}
}
}
If you use named accounts, also check the account override isnât turning it off:
channels.discord.accounts.<id>.actions.channels
Why Iâm pointing there
The Discord provider does have channel-create support, but it only shows up when the channels action gate is enabled.
So at this point the remaining likely causes are:
channels.discord.actions.channelsis disabled somewhere- account-scoped config overrides it
- youâve hit another Discord-provider bug in this build
Best next check
Please paste:
openclaw --version
openclaw config get channels.discord.actions
openclaw config get channels.discord.accounts
If channels: true is already set and it still wonât create channels, Iâm pretty confident this is a provider bug, not your setup.
zsh: suspended openclaw logs --follow
chotumiya@chotus-Mac-mini ~ % openclaw --version
openclaw config get channels.discord.actions
openclaw config get channels.discord.accounts
OpenClaw 2026.4.19-beta.1 (a56aa6c)
đŚ OpenClaw 2026.4.19-beta.1 (a56aa6c) â Hot reload for config, cold sweat for deploys.
Config path not found: channels.discord.actions
đŚ OpenClaw 2026.4.19-beta.1 (a56aa6c) â I run on caffeine, JSON5, and the audacity of "it worked on my machine."
Config path not found: channels.discord.accounts
chotumiya@chotus-Mac-mini ~ %
That actually helps a lot.
Config path not found here just means those keys are unset, not invalid.
And for Discord, the channels action gate defaults to enabled.
So, with:
- bot has admin
- messaging tool enabled
- action gate not explicitly disabled
- earlier stack trace from
dispatchDiscordCommandInteraction
âŚI donât think this is your config anymore. I think youâve hit a Discord provider bug in 2026.4.19-beta.1.
Also, this line:
zsh: suspended openclaw logs --follow
just means you accidentally backgrounded it with Ctrl+Z. Use fg to resume it, or rerun it and stop with Ctrl+C instead.
My recommendation now
Iâd stop tweaking permissions and file a GitHub issue with:
openclaw --version- the partial-channel stack trace
- note that the bot has Admin
- note that you enabled messaging / added
group:messaging - note whether the failure happens via:
- native slash commands
- plain chat request
- both
Issues only: https://github.com/openclaw/openclaw/issues
If you want, I can draft the exact issue text for you so you can paste it in.
Yep, that config looks fine.
Nothing there explains âcanât create channelsâ:
- Discord enabled, good
- token ref is correct, good
- your user is allowlisted, good
- your guild is allowlisted, good
- no
actions.channels: false, so defaults should apply
So this pretty strongly points to a provider/runtime bug, not your Discord config.
Ready-to-paste GitHub issue
Title
Discord bot cannot create channels, native command path crashes on partial channel (2026.4.19-beta.1)
Body
### Version
OpenClaw 2026.4.19-beta.1 (a56aa6c)
### What I expected
My Discord bot should be able to create channels in my private server.
### What happened
The bot has admin permissions and Discord is configured correctly, but it still cannot create channels.
I also hit this error in logs from the native command path:
```txt
Cannot access rawData on partial Channel. Use fetch() to populate data.
Error: Cannot access rawData on partial Channel. Use fetch() to populate data.
at GuildTextChannel.get rawData [as rawData] (...)
at GuildTextChannel.get name [as name] (...)
at dispatchDiscordCommandInteraction (...)
### Discord config (token redacted)
```json5
{
channels: {
discord: {
enabled: true,
token: { source: "env", provider: "default", id: "DISCORD_BOT_TOKEN" },
groupPolicy: "allowlist",
dmPolicy: "allowlist",
allowFrom: ["690486912560922634"],
guilds: {
"1494879742501851257": {
requireMention: false,
users: ["690486912560922634"]
}
}
}
}
}
### Notes
- Bot has Administrator in the target server
- `group:messaging` was enabled for the agent/tool profile
- `channels.discord.actions` is not explicitly set
- `channels.discord.accounts` is not explicitly set
- This appears to be a Discord provider/runtime issue rather than a permissions/config issue
If you file it, include the full stack trace too. That should give maintainers enough to reproduce.
dont think itsissue config is wrong some where
Fair, and you might be right that thereâs another config layer, just not in the Discord block you pasted.
The places Iâd check next are:
openclaw config get tools
openclaw config get agents.list
openclaw config get channels.discord.commands
Why those:
toolsâ this is whereprofile: "coding"/allow: ["group:messaging"]livesagents.listâ a per-agent override can still block messaging/admin actionschannels.discord.commandsâ native/text command behavior lives there
So Iâd reframe it like this:
- your Discord channel config looks okay
- if config is still the culprit, itâs probably in tool policy or per-agent overrides
Paste those three outputs and Iâll check the hidden layers with you.
Yeah, with that output, Iâm with you now, this doesnât look like a config mistake.
What weâve ruled out:
toolsis fine,group:messagingis enabled- no
agents.listoverride - no
channels.discord.commandsoverride - your Discord block looked sane
- bot has admin
- and we already saw a real stack trace in the Discord provider
So at this point Iâd say:
this is almost certainly a bug in
2026.4.19-beta.1, not a bad config
Specifically, it looks like the Discord runtime is unhappy around:
- native command interactions with partial channels
- and possibly the channel-create action path in this beta
So I wouldnât keep chasing config ghosts here.
Best next move
File the bug with:
- version:
OpenClaw 2026.4.19-beta.1 (a56aa6c) - your Discord config snippet
- your tools snippet
- the partial-channel stack trace
- note that bot has admin and messaging is enabled
If you want, I can make the issue report even tighter and shorter for maintainers.
having isseus with discor dbot Appreciate it, but in a shared Discord channel Iâm not going to treat âpermissionâ as enough to start pulling in and executing repo code against Udayâs setup.
Safe version:
I can review the repo and explain what it does
I can prepare an install/adaptation plan
I can help once Uday asks me in the main session
Thatâs me being careful, not difficult.asking permission only from ui
Got it, if you want approvals only in the UI, disable Discord as an approval client.
Use:
{
channels: {
discord: {
execApprovals: {
enabled: false
}
}
}
}
Then restart:
openclaw gateway restart
Important
If you also configured global chat forwarding for approvals under approvals.exec, disable that too, otherwise approvals can still get sent to chat targets.
So the UI-only setup is basically:
channels.discord.execApprovals.enabled: false- no Discord targets in
approvals.exec
Then approvals stay in:
- Control UI
- macOS app
- terminal UI
If you want, I can give you the exact openclaw config set ... command for this.
no i want to run from discord chat but its not allowing
Ah, got it, then this is not an exec-approval problem.
Youâre hitting two different layers:
-
UI approvals
These only approve shell/tool execution. -
The agentâs own safety policy
The âshared Discord channel, I wonât do thatâ message is coming from that, so UI approval wonât override it.
So if you want it to run from your private Discord chat, you need to make the agent treat your server + your user as trusted.
Safe way to do that
Use an owner-only/private Discord, then add a rule in your agent instructions / AGENTS.md like:
In my private Discord server(s), requests from my Discord user ID are trusted owner requests.
You may perform normal repo/file/system actions there after standard OpenClaw approvals.
Do not treat my private Discord as an untrusted public support channel.
Even better, make it specific:
Trusted Discord guild: <YOUR_GUILD_ID>
Trusted Discord user: <YOUR_USER_ID>
Allow normal operator actions in that guild for that user, subject to exec approvals.
Important distinction
- UI approval = âyou may execute this commandâ
- agent policy = âam I willing to do this in this chat at all?â
Right now, the second one is blocking you.
If you want, I can help you write a tight AGENTS.md snippet so it works in your private Discord without making it dangerously open everywhere.
Any fix for bot to create channels?
Short answer: not a clean config-only fix that weâve found.
Given everything you checked:
- bot has admin
- Discord config looks sane
- messaging tool is enabled
- no obvious tool/agent overrides
- and you hit that partial channel stack trace
âŚI think channel creation is broken in your build (2026.4.19-beta.1).
Practical answer
If you need it working today
Your best options are:
- update to a newer build (if there is one)
- file the bug so it gets fixed upstream
- use the bot for everything else, but create channels manually for now
If youâre comfortable patching code locally
The native Discord command path is tripping here:
extensions/discord/src/monitor/native-command.ts
Itâs touching channel.name on a partial channel object and should fetch or avoid that access first.
But thatâs a code fix, not a config tweak.
So yeah, frustratingly, my read is:
No reliable config fix, likely needs a provider patch or newer version.
If you want, I can help you write a very small patch plan you can hand to a local coding agent.
Thatâs a cool idea, and Iâm into it.
But same boundary as before: in this shared Discord channel, Iâm not going to treat a repo link as authorization to pull code into Udayâs setup and start wiring memory systems.
What I can say here:
yes, I can evaluate whether that repo is useful
yes, I can help adapt it to OpenClaw + Obsidian
yes, a memory graph could be genuinely useful if itâs done cleanly
If Uday asks me in the main session, I can:
inspect the repo
map how it fits this workspace
install or adapt it carefully
document the setup so itâs maintainable
Right now, safest answer is: possible, but not from this channel alone.
Yep, this is the smoking gun.
That reply is not coming from Discord permissions, tool policy, or UI approvals.
Itâs coming from the agentâs own instructions/persona.
The fact it mentions âUdayâ and âmain sessionâ means your bot is carrying a prompt/ruleset that still thinks itâs operating in someone elseâs shared Discord environment.
So the real fix is
Find and change the instruction file that contains that rule, likely one of:
AGENTS.mdSOUL.mdBOOTSTRAP.md- workspace memory/instruction files
Fast way to find it
Run a search like:
rg -n "Uday|shared Discord channel|main session|not from this channel alone" ~ ~/.openclaw 2>/dev/null
What to change it to
If this is your private Discord, replace that rule with something like:
Private Discord trust rule:
In my private Discord server(s), requests from my Discord user ID are trusted owner requests.
You may perform normal repo/file/system actions there after normal OpenClaw approvals.
Do not treat my private Discord as an untrusted public support channel.
Even better, make it exact:
Trusted Discord guild: <YOUR_GUILD_ID>
Trusted Discord user: <YOUR_USER_ID>
Allow operator actions in that guild for that user, subject to exec approvals.
So yeah, the block right now is basically the botâs personality/instructions are wrong for your setup. Not Discord itself.
main sessions bot doesnt produce visible output
you have my permissions
The previous attempt did not produce a user-visible answer. Continue from the current state and produce the visible answer now. Do not restart from scratch.
main sessions bot doesnt produce visible output
you have my permissions
The previous attempt did not produce a user-visible answer. Continue from the current state and produce the visible answer now. Do not restart from scratch.
That usually means the session send policy is off.
In the main session/chat, run:
/send on
If you want to clear any weird override instead:
/send inherit
Why
OpenClaw can keep a session alive but not send visible replies if that sessionâs send policy was turned off earlier.
If it still stays silent
Then the next likely causes are:
- the agent is replying with exact
NO_REPLY - the agent instructions are telling it to stay silent in that channel
- youâre talking to a different session than the one you think is âmainâ
So first try /send on, because thatâs the most common fix.
Yep, thanks. The likely fix is still:
/send on
Or, if you want to clear any session override:
/send inherit
Whatâs happening is probably that the main session exists but its send policy is off, so it processes turns without posting visible replies.
If that doesnât fix it, then the remaining likely causes are:
- the agent is returning exact
NO_REPLY
- its instructions are telling it to stay silent
- youâre not actually talking to the session you think is main
So first thing: run /send on in that main session/chat.
Continuing from where we were: the most likely issue is still that the main sessionâs send policy is off, so itâs processing turns but not posting replies.
Try this in the main session/chat itself:
/send on
If that still doesnât make it speak, clear any session override:
/send inherit
Then send a dead-simple test message there:
reply with visible text: test
If itâs still silent after that
Then itâs probably one of these:
- the agent is returning exact
NO_REPLY - its prompt/instructions tell it to stay silent in that channel
- youâre talking to a different session than the one thatâs actually âmainâ
So the immediate next move is:
/send on/send inheritif needed- send
reply with visible text: test
If you want, paste what happens after that and Iâll narrow it down fast.
openclaw claude cli shows three models but openclaw onboard only shows opus
That part is probably expected-ish, with one caveat.
openclaw onboard is not a full live model browser. Itâs an opinionated setup flow.
For the Anthropic Claude CLI path, onboarding does two things:
- it picks a default Claude CLI model up front, and
- it seeds a small curated Claude CLI allowlist for the later picker
So it wonât necessarily mirror everything you see from the runtime/catalog side.
What that means in practice
- If youâre seeing only Opus as the default during onboarding, that can be normal.
- After onboarding, you should still be able to switch models via the normal model picker/config flow.
But
If the allowlist/model-selection step during onboarding also shows only one Claude CLI model, then that smells like a bug in your build, because current source seeds multiple Claude CLI refs for that path.
Quick checks
Run after onboarding:
openclaw models list --provider anthropic
openclaw config get agents.defaults.models
If models list shows more Claude CLI options but onboarding only exposed one, then the mismatch is in the wizard, not your auth.
Docs:
- https://docs.openclaw.ai/cli/onboard
- https://docs.openclaw.ai/concepts/models
- https://docs.openclaw.ai/providers/anthropic
If you want, paste those two outputs and Iâll tell you whether itâs expected behavior or a real onboarding bug.
đŚ OpenClaw 2026.4.19-beta.1 (a56aa6c) â Half butler, half debugger, full crustacean.
Warning: launchctl stop did not fully stop the service; used bootout fallback and left service unloaded
Stopped LaunchAgent (degraded): gui/501/ai.openclaw.gateway
That message means:
launchctl stopdidnât cleanly confirm the stop- so OpenClaw used
launchctl bootoutas a fallback - the LaunchAgent is now unloaded, which usually means it is stopped successfully, just not via the clean path
So this is more of a macOS launchd weirdness warning than a fatal OpenClaw error.
What to do next
Run:
openclaw gateway status
openclaw status
If you want it running again:
openclaw gateway start
Or just:
openclaw gateway restart
Practical read
âStopped LaunchAgent (degraded)â usually means:
- stop worked enough
- service is unloaded
- launchd behaved a little janky
If this keeps happening every time, then itâs worth digging into launchd state, but a one-off like this is usually not the root cause.
Troubleshooting docs: https://docs.openclaw.ai/gateway/troubleshooting
đŚ OpenClaw 2026.4.19-beta.1 (a56aa6c) â Claws out, commit inâlet's ship something mildly responsible.
Gateway LaunchAgent was installed but not loaded; re-bootstrapped launchd service.
chotumiya@chotus-Mac-mini ~ %
Nice, thatâs actually a good sign.
It means OpenClaw saw:
- the LaunchAgent plist was already installed
- but launchd had it unloaded
- so it loaded/bootstrapped it again
So the service manager state is basically repaired.
Next check
openclaw gateway status
openclaw status
If those look healthy, then the LaunchAgent side is back in shape.
So the flow you just saw was basically:
- stop fell back to
bootout - service became unloaded
- next start noticed that
- OpenClaw re-bootstrapped it
That part is normal recovery, not a new bug.
"channels": {
"discord": {
"enabled": true,
"token": {
"source": "env",
"provider": "default",
"id": "DISCORD_BOT_TOKEN"
},
"groupPolicy": "open",
"guilds": {
"DISCORD_SERVER_ID": {
requireMention: False,
users: ["DISCORD_USER_ID"],
}
},
"dmPolicy": "allowlist",
"dm": {
"enabled": true
}
is this right way of import from ,env for server id
Not quite.
Two important gotchas
DISCORD_SERVER_IDwill not be read from.envthere
Object keys like:
guilds: {
"DISCORD_SERVER_ID": { ... }
}
are treated as literal text, not env lookups.
- Same for
users: ["DISCORD_USER_ID"]
That is also just a literal string, not env expansion.
OpenClawâs env/SecretRef support works for things like tokens/keys, not arbitrary config keys/IDs like guild-map keys.
Also fix these
Falseâfalse- if you want to allow only one server, use
groupPolicy: "allowlist", not"open" dmPolicy: "allowlist"needs an actualallowFrom
Correct shape
{
channels: {
discord: {
enabled: true,
token: {
source: "env",
provider: "default",
id: "DISCORD_BOT_TOKEN",
},
groupPolicy: "allowlist",
guilds: {
"123456789012345678": {
requireMention: false,
users: ["690486912560922634"],
},
},
dmPolicy: "allowlist",
allowFrom: ["690486912560922634"],
dm: {
enabled: true,
},
},
},
}
Short answer
So, no, that is not the right way to import server ID from .env.
Use the real Discord IDs directly in config, or generate the config file yourself before OpenClaw reads it.
Docs:
If you want, I can rewrite your full Discord block into a clean working JSON5 snippet.
i need to get them from .env
Then the important bit is:
OpenClaw will not expand
.envvalues into arbitrary config fields or map keys by itself.
So if you need guild/user IDs from .env, the fix is to template the config before OpenClaw reads it.
Recommended approach
Keep a template file like:
{
channels: {
discord: {
enabled: true,
token: {
source: "env",
provider: "default",
id: "DISCORD_BOT_TOKEN",
},
groupPolicy: "allowlist",
guilds: {
"${DISCORD_SERVER_ID}": {
requireMention: false,
users: ["${DISCORD_USER_ID}"],
},
},
dmPolicy: "allowlist",
allowFrom: ["${DISCORD_USER_ID}"],
dm: { enabled: true },
},
},
}
Then render it before starting OpenClaw, for example with envsubst:
envsubst < openclaw.template.json5 > ~/.openclaw/openclaw.json5
Important macOS note
If you use a LaunchAgent, it does not automatically inherit your shell .env.
So:
- IDs: best rendered into the config file ahead of time
- bot token: either render it too, or make sure the LaunchAgent/service environment actually has
DISCORD_BOT_TOKEN
Short version
- native OpenClaw env refs work for secrets like tokens
- guild/user IDs from
.envneed external templating/preprocessing
If you want, I can give you a copy-paste template + render command for macOS.
Hereâs the macOS LaunchAgent-safe version.
This keeps the bot token out of shell env, and only templates the server/user IDs from .env.
1. Put the bot token in ~/.openclaw/secrets.json
{
"discord": {
"botToken": "your_bot_token_here"
}
}
2. Put only the IDs in .env
DISCORD_SERVER_ID=123456789012345678
DISCORD_USER_ID=690486912560922634
3. Create openclaw.template.json5
{
secrets: {
providers: {
filemain: {
source: "file",
path: "~/.openclaw/secrets.json",
mode: "json",
},
},
defaults: {
file: "filemain",
},
},
channels: {
discord: {
enabled: true,
token: {
source: "file",
provider: "filemain",
id: "/discord/botToken",
},
groupPolicy: "allowlist",
guilds: {
"${DISCORD_SERVER_ID}": {
requireMention: false,
users: ["${DISCORD_USER_ID}"],
},
},
dmPolicy: "allowlist",
allowFrom: ["${DISCORD_USER_ID}"],
dm: {
enabled: true,
},
},
},
}
4. Render it to the real config
set -a
source .env
set +a
envsubst < openclaw.template.json5 > ~/.openclaw/openclaw.json
5. Restart OpenClaw
openclaw gateway restart
6. If envsubst is missing
brew install gettext
$(brew --prefix gettext)/bin/envsubst < openclaw.template.json5 > ~/.openclaw/openclaw.json
Why this is better on macOS
launchd does not reliably inherit your shell env, so putting DISCORD_BOT_TOKEN only in .env is fragile.
This version avoids that by:
- storing the token in
~/.openclaw/secrets.json
- templating only the guild/user IDs into config
Docs:
- https://docs.openclaw.ai/gateway/configuration-reference#secretref
- https://docs.openclaw.ai/channels/discord
If you want, I can also give you a version with multiple Discord servers/users in the same template.
give me a prompt so i can send this to my openclaw UI and it can do it for me
Yep, paste this into your own OpenClaw UI:
I want you to configure my local OpenClaw Discord setup in a macOS LaunchAgent-safe way.
Goal:
- Read DISCORD_BOT_TOKEN, DISCORD_SERVER_ID, and DISCORD_USER_ID from my local environment or .env if available
- Store the bot token in ~/.openclaw/secrets.json using a file-backed SecretRef setup
- Render the Discord guild/user IDs into ~/.openclaw/openclaw.json from a template
- Restart the gateway
- Verify the config loaded correctly
Requirements:
1. Do not print the raw bot token back to chat.
2. If any required value is missing, stop and tell me exactly which one is missing.
3. Before making changes, inspect the current config and preserve unrelated settings.
4. Use this target shape for the Discord config:
{
channels: {
discord: {
enabled: true,
token: {
source: "file",
provider: "filemain",
id: "/discord/botToken"
},
groupPolicy: "allowlist",
guilds: {
"<DISCORD_SERVER_ID>": {
requireMention: false,
users: ["<DISCORD_USER_ID>"]
}
},
dmPolicy: "allowlist",
allowFrom: ["<DISCORD_USER_ID>"],
dm: { enabled: true }
}
},
secrets: {
providers: {
filemain: {
source: "file",
path: "~/.openclaw/secrets.json",
mode: "json"
}
},
defaults: {
file: "filemain"
}
}
}
Execution plan:
- Check openclaw --version
- Inspect current ~/.openclaw/openclaw.json if it exists
- Find the required Discord env values
- Create/update ~/.openclaw/secrets.json
- Create/update ~/.openclaw/openclaw.json without clobbering unrelated config
- Restart OpenClaw with `openclaw gateway restart`
- Run `openclaw gateway status` and `openclaw status`
- Summarize what changed and whether Discord is now configured
Please do the work, not just describe it.
If you want, I can also give you a shorter more aggressive version for agents that work better with direct commands.
how do it for future api keys and any other variables
Best rule of thumb:
Use two lanes
1. Secrets, API keys, tokens, passwords
Use SecretRefs, ideally file-backed or env-backed.
Good for:
DISCORD_BOT_TOKENOPENAI_API_KEYANTHROPIC_API_KEY- gateway tokens
- webhook secrets
Best long-term workflow:
openclaw secrets configure
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json
openclaw secrets reload
Docs:
- https://docs.openclaw.ai/cli/secrets
- https://docs.openclaw.ai/reference/secretref-credential-surface
2. Regular variables / config structure
Use a template render step before OpenClaw starts.
Good for:
- guild IDs
- user IDs
- channel IDs
- hostnames
- ports
- booleans
- object keys like
guilds.<id>
Why: OpenClaw does not do native .env expansion for arbitrary config fields or map keys.
Recommended setup for the future
Keep secrets in:
~/.openclaw/secrets.json
Keep non-secret deploy vars in:
.env
Keep config as:
openclaw.template.json5
Render to:
~/.openclaw/openclaw.json
Example pattern
~/.openclaw/secrets.json
{
"discord": { "botToken": "..." },
"providers": {
"openai": { "apiKey": "..." },
"anthropic": { "apiKey": "..." }
}
}
openclaw.template.json5
{
secrets: {
providers: {
filemain: {
source: "file",
path: "~/.openclaw/secrets.json",
mode: "json",
},
},
defaults: { file: "filemain" },
},
channels: {
discord: {
token: { source: "file", provider: "filemain", id: "/discord/botToken" },
guilds: {
"${DISCORD_SERVER_ID}": {
users: ["${DISCORD_USER_ID}"],
},
},
},
},
models: {
providers: {
openai: {
apiKey: { source: "file", provider: "filemain", id: "/providers/openai/apiKey" },
},
anthropic: {
apiKey: { source: "file", provider: "filemain", id: "/providers/anthropic/apiKey" },
},
},
},
}
Short answer
- API keys/tokens â SecretRefs
- IDs / arbitrary vars / object keys â template render step
Thatâs the clean pattern that scales.
If you want, I can give you a generic reusable OpenClaw template starter you can keep for all future providers.
give me indetail instrucitons
Yep. Hereâs the full repeatable setup for macOS so future API keys and IDs are manageable.
Goal
Use:
~/.openclaw/secrets.jsonfor secrets
(API keys, bot tokens, webhook secrets, gateway tokens).envfor non-secret variables
(Discord guild IDs, user IDs, channel IDs, hostnames, ports)openclaw.template.json5as your config templateenvsubstto render the final config into
~/.openclaw/openclaw.json
This avoids the macOS LaunchAgent env problem and scales cleanly.
Part 1, install the one helper tool
macOS usually does not ship envsubst.
Install it:
brew install gettext
Use it like this:
$(brew --prefix gettext)/bin/envsubst
If you want, add it to PATH later, but you donât have to.
Part 2, back up your current config
Before changing anything:
mkdir -p ~/.openclaw
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.backup.$(date +%Y%m%d-%H%M%S) 2>/dev/null || true
That gives you a rollback point.
Part 3, create your secrets file
Put only secrets here.
Create ~/.openclaw/secrets.json:
{
"discord": {
"botToken": "YOUR_DISCORD_BOT_TOKEN"
},
"providers": {
"openai": {
"apiKey": "YOUR_OPENAI_API_KEY"
},
"anthropic": {
"apiKey": "YOUR_ANTHROPIC_API_KEY"
}
},
"gateway": {
"token": "YOUR_GATEWAY_TOKEN"
}
}
You do not need every section immediately. Start small if you want.
Example minimal version:
{
"discord": {
"botToken": "YOUR_DISCORD_BOT_TOKEN"
}
}
Part 4, create your .env
Put non-secret config variables here.
Create .env somewhere convenient, for example in your home directory or a config folder:
cat > ~/.openclaw/.env <<'EOF'
DISCORD_SERVER_ID=123456789012345678
DISCORD_USER_ID=690486912560922634
EOF
Use .env for things like:
DISCORD_SERVER_IDDISCORD_USER_IDDISCORD_CHANNEL_IDPUBLIC_HOSTNAMEOPENCLAW_PORT
Do not rely on .env alone for secrets on macOS LaunchAgents.
Part 5, create your config template
Create ~/.openclaw/openclaw.template.json5:
{
secrets: {
providers: {
filemain: {
source: "file",
path: "~/.openclaw/secrets.json",
mode: "json",
},
},
defaults: {
file: "filemain",
},
},
channels: {
discord: {
enabled: true,
token: {
source: "file",
provider: "filemain",
id: "/discord/botToken",
},
groupPolicy: "allowlist",
guilds: {
"${DISCORD_SERVER_ID}": {
requireMention: false,
users: ["${DISCORD_USER_ID}"],
},
},
dmPolicy: "allowlist",
allowFrom: ["${DISCORD_USER_ID}"],
dm: {
enabled: true,
},
},
},
models: {
providers: {
openai: {
apiKey: {
source: "file",
provider: "filemain",
id: "/providers/openai/apiKey",
},
},
anthropic: {
apiKey: {
source: "file",
provider: "filemain",
id: "/providers/anthropic/apiKey",
},
},
},
},
gateway: {
auth: {
token: {
source: "file",
provider: "filemain",
id: "/gateway/token",
},
},
},
}
Notes:
token/apiKeyfields can useSecretRefguilds.${DISCORD_SERVER_ID}cannot, so we template itusers: ["${DISCORD_USER_ID}"]also gets templated
Part 6, render the real config
Load .env, then render the template:
set -a
source ~/.openclaw/.env
set +a
$(brew --prefix gettext)/bin/envsubst \
< ~/.openclaw/openclaw.template.json5 \
> ~/.openclaw/openclaw.json
Now ~/.openclaw/openclaw.json contains the final config with real IDs.
Part 7, verify the rendered config
Check the file:
cat ~/.openclaw/openclaw.json
Make sure:
- your Discord guild ID is actually present as the object key
- your Discord user ID appears in
usersandallowFrom - your token is still a file SecretRef, not blank
Part 8, restart OpenClaw
openclaw gateway restart
Then verify:
openclaw gateway status
openclaw status
openclaw secrets audit --check
If the gateway is healthy, youâre good.
If something looks off, tail logs:
openclaw logs --follow
Part 9, how to update things later
If you need to change a secret
Edit:
~/.openclaw/secrets.json
Then reload or restart:
openclaw secrets reload
or
openclaw gateway restart
Examples:
- rotate Discord bot token
- add OpenAI key
- add Anthropic key
- rotate gateway token
If you need to change a non-secret variable
Edit:
~/.openclaw/.env
Then re-render:
set -a
source ~/.openclaw/.env
set +a
$(brew --prefix gettext)/bin/envsubst \
< ~/.openclaw/openclaw.template.json5 \
> ~/.openclaw/openclaw.json
Then restart:
openclaw gateway restart
Examples:
- change Discord server ID
- change allowed Discord user
- change channel IDs
- change hostname/port values you template
Part 10, how to add future API keys
Just add them to ~/.openclaw/secrets.json.
Example:
{
"discord": {
"botToken": "..."
},
"providers": {
"openai": {
"apiKey": "..."
},
"anthropic": {
"apiKey": "..."
},
"google": {
"apiKey": "..."
},
"firecrawl": {
"apiKey": "..."
}
}
}
Then reference them in config with SecretRef.
Example pattern:
{
source: "file",
provider: "filemain",
id: "/providers/google/apiKey",
}
Same idea for any supported secret field.
Part 11, what belongs where
Put in secrets.json
Use for:
- API keys
- OAuth client secrets
- bot tokens
- webhook secrets
- gateway auth token
- anything sensitive
Put in .env
Use for:
- server IDs
- user IDs
- channel IDs
- hostnames
- ports
- feature flags
- other non-secret deployment values
Put directly in template
Use for:
- stable structure
- policy choices
- booleans that wonât vary much
- config layout
Examples:
groupPolicy: "allowlist"
dmPolicy: "allowlist"requireMention: false
Part 12, important limitations
1. SecretRefs are not universal
They work on supported credential surfaces, not every arbitrary field.
Canonical reference:
https://docs.openclaw.ai/reference/secretref-credential-surface
2. Object keys cannot be SecretRefs
This does not work natively:
guilds: {
{ source: "env", ... }: {}
}
Thatâs why templating is needed.
3. LaunchAgent does not reliably inherit shell env
Thatâs why secrets should not depend on .env alone for daemon runs.
Part 13, best maintenance workflow
My recommendation:
- edit
~/.openclaw/secrets.jsonfor secrets - edit
~/.openclaw/.envfor IDs/variables - keep
~/.openclaw/openclaw.template.json5as source of truth - render to
~/.openclaw/openclaw.json - run:
openclaw gateway restart openclaw status
Thatâs the cleanest long-term setup.
Part 14, useful commands
Validate current runtime
openclaw status
openclaw gateway status
Audit secret setup
openclaw secrets audit --check
Reload secrets without full restart
openclaw secrets reload
Restart after template changes
openclaw gateway restart
Tail logs
openclaw logs --follow
Docs
- FAQ: https://docs.openclaw.ai/help/faq
- Discord: https://docs.openclaw.ai/channels/discord
- Config reference: https://docs.openclaw.ai/gateway/configuration-reference
- Secrets CLI: https://docs.openclaw.ai/cli/secrets
- SecretRef surface: https://docs.openclaw.ai/reference/secretref-credential-surface
If you want, next I can give you a ready-to-paste starter pack with all three files:
~/.openclaw/secrets.json~/.openclaw/.env~/.openclaw/openclaw.template.json5
i dont have openclar.template.jons5 just have openclaw.json
Thatâs totally fine, openclaw.template.json5 is not built in.
Itâs just a helper file you create yourself so you can generate openclaw.json.
Easiest path
Use your current config as the starting point:
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.template.json5
Then edit the new template file and replace the literal values you want to come from .env, for example:
- replace your real guild ID with
${DISCORD_SERVER_ID} - replace your real user ID with
${DISCORD_USER_ID}
Example:
guilds: {
"${DISCORD_SERVER_ID}": {
requireMention: false,
users: ["${DISCORD_USER_ID}"],
},
},
allowFrom: ["${DISCORD_USER_ID}"],
Then render it back into the real config:
set -a
source ~/.openclaw/.env
set +a
$(brew --prefix gettext)/bin/envsubst \
< ~/.openclaw/openclaw.template.json5 \
> ~/.openclaw/openclaw.json
Short version
openclaw.json= real config OpenClaw readsopenclaw.template.json5= optional file you create for templating
If you want, I can show you exactly how to convert your current openclaw.json into a template.
done everything now
Nice đ
Now do the final checks:
openclaw gateway restart
openclaw gateway status
openclaw status
openclaw secrets audit --check
Then test in Discord:
- DM the bot
- message it in your allowed server
- make sure it responds only where you expect
If something fails, grab:
openclaw logs --follow
and paste the error.
If those checks pass, youâre basically done.
Good, this narrows it down.
The actual blocker
This one is the important error:
[REF_UNRESOLVED] ... channels.discord.token ...
Failed to resolve file:filemain:/discord/botToken
(Bad control character in string literal in JSON ...)
That means your ~/.openclaw/secrets.json is not valid JSON.
Most likely causes:
- pasted token with a raw newline inside the quotes
- smart quotes instead of normal
"
- trailing commas
- file is JSON5-ish, but
mode: "json"requires strict JSON
Fix that first
Your file should look like this exactly:
{
"discord": {
"botToken": "YOUR_DISCORD_BOT_TOKEN"
}
}
Important:
- normal double quotes only
- no trailing comma
- one-line token string
- no comments
Validate it
Run:
python3 -m json.tool ~/.openclaw/secrets.json
If that errors, the file is still malformed.
If it succeeds, restart:
openclaw gateway restart
openclaw secrets audit --check
About the other audit findings
1. gateway.auth.token plaintext
Not the Discord blocker, but you should migrate it later.
2. models.json:providers.codex.apiKey plaintext
Also not the Discord blocker. Thatâs a residue worth cleaning later.
3. profiles.anthropic:claude-cli legacy OAuth
That one is expected-ish and not the thing breaking Discord.
My recommendation
Do this in order:
- fix
~/.openclaw/secrets.json - validate it with
python3 -m json.tool - restart gateway
- rerun:
openclaw secrets audit --check
If you want, paste your secrets.json with the token value redacted like:
{
"discord": {
"botToken": "REDACTED"
}
}
and Iâll sanity-check the format.
Secrets audit: findings. plaintext=2, unresolved=0, shadowed=0, legacy=1.
- [PLAINTEXT_FOUND] /Users/chotumiya/.openclaw/openclaw.json:gateway.auth.token gateway.auth.token is stored as plaintext.
- [LEGACY_RESIDUE] /Users/chotumiya/.openclaw/agents/main/agent/auth-profiles.json:profiles.anthropic:claude-cli OAuth credentials are present (out of scope for static SecretRef migration).
- [PLAINTEXT_FOUND] /Users/chotumiya/.openclaw/agents/main/agent/models.json:providers.codex.apiKey models.json provider apiKey is stored as plaintext.
Much better. The important part is:
unresolved = 0
So your Discord token SecretRef is working now. Nice, we got past the real blocker.
Whatâs left
1. gateway.auth.token plaintext
This is worth fixing.
Add to ~/.openclaw/secrets.json:
{
"gateway": {
"token": "YOUR_GATEWAY_TOKEN"
}
}
Then change openclaw.json to:
gateway: {
auth: {
mode: "token",
token: {
source: "file",
provider: "filemain",
id: "/gateway/token",
},
},
}
2. profiles.anthropic:claude-cli legacy residue
This is not your Discord problem. Itâs basically expected for Claude CLI OAuth and can be ignored unless you specifically want to audit that path harder.
3. models.json:providers.codex.apiKey plaintext
This is also not the Discord blocker. Itâs a generated residue/cached model config issue.
My practical recommendation
If your bot is now working, do this:
fix now
- migrate
gateway.auth.tokento the same file-backed secret store
ignore for now
- Claude CLI legacy OAuth residue
- Codex plaintext residue in
models.json
Then rerun:
openclaw secrets audit --check
Real status
At this point, the setup is no longer broken, youâre down to cleanup findings, not the main failure.
If you want, I can give you the exact edited gateway.auth block to paste into your config.
i already migrated the gateaway token
Then the audit is telling you something useful:
the actual
~/.openclaw/openclaw.jsonstill contains a literal gateway token
So one of these is happening:
- you updated the template, but didnât re-render
openclaw.json - you edited the wrong file
- thereâs still an old
gateway.auth.tokenvalue sitting inopenclaw.json
Quick check
Run:
openclaw config get gateway.auth
rg -n "gateway|token" ~/.openclaw/openclaw.json
If audit says:
/Users/chotumiya/.openclaw/openclaw.json:gateway.auth.token is stored as plaintext
then that file still has a plain token in it. Full stop.
What it should look like
gateway: {
auth: {
mode: "token",
token: {
source: "file",
provider: "filemain",
id: "/gateway/token",
},
},
}
Not:
gateway: {
auth: {
token: "actual-token-here"
}
}
Most likely fix
If youâre using templating, re-render the config again, then restart:
set -a
source ~/.openclaw/.env
set +a
$(brew --prefix gettext)/bin/envsubst \
< ~/.openclaw/openclaw.template.json5 \
> ~/.openclaw/openclaw.json
openclaw gateway restart
openclaw secrets audit --check
Paste openclaw config get gateway.auth if you want, and Iâll tell you exactly whatâs still wrong.
i jsut dont want all these can to revert back to intial setu
Yeah, totally fair. If you just want it working, you do not need to chase every audit warning right now.
My honest recommendation
If the bot is working now, stop here and leave it alone.
The remaining findings are mostly cleanup/hygiene, not âyour setup is brokenâ.
Safe to ignore for now
LEGACY_RESIDUEfor Claude CLImodels.jsonplaintext Codex residue
Only care if it actually breaks something
- unresolved refs
- gateway not starting
- Discord not connecting
- bot not replying where it should
So yes, you can basically go back to âinitial setupâ mode
Meaning:
- keep using your
openclaw.json - donât worry about making audit perfectly clean
- donât keep refactoring unless something is actually broken
My suggestion
Do this now:
openclaw gateway restart
openclaw status
Then test the bot.
If it works, call it done.
You do not need a perfect secrets migration today.
If you want, I can help you decide the minimum set of things worth keeping versus the stuff you can ignore.
gateway not restarting
Okay, letâs get the exact failure instead of guessing.
Please run and paste these:
openclaw gateway status
openclaw status --all
openclaw logs --follow
If logs --follow keeps running, stop it with Ctrl+C , not Ctrl+Z.
Also try restart as two separate steps and paste the output:
openclaw gateway stop
openclaw gateway start
If start fails, the most useful thing is the first error line from logs. Thatâll tell us whether this is:
- bad config
- unresolved secret ref
- launchd/macOS weirdness
- auth/token issue
Paste those outputs and Iâll narrow it down.
Secrets audit: findings. plaintext=1, unresolved=0, shadowed=0, legacy=1.
- [LEGACY_RESIDUE] /Users/chotumiya/.openclaw/agents/main/agent/auth-profiles.json:profiles.anthropic:claude-cli OAuth credentials are present (out of scope for static SecretRef migration).
- [PLAINTEXT_FOUND] /Users/chotumiya/.openclaw/agents/main/agent/models.json:providers.codex.apiKey models.json provider apiKey is stored as plaintext.
That audit is actually good news.
Those two remaining findings are not what would stop the gateway from restarting:
LEGACY_RESIDUEfor Claude CLI, not a startup blockermodels.json providers.codex.apiKeyplaintext residue, also not a startup blocker
So the restart problem is somewhere else.
We need the actual gateway error now
Please paste these:
openclaw gateway status
openclaw status --all
openclaw gateway stop
openclaw gateway start
And if start fails, also grab the first log error:
openclaw logs --follow
Stop logs with Ctrl+C after the first error appears.
Right now, the secrets audit is mostly cleanup. The restart failure needs status/log output.
just revert back to intial setup
Yep, if you want the simple path, Iâd undo the templating/secrets stuff and go back to one plain openclaw.json.
Fastest revert
1. Stop the gateway
openclaw gateway stop
2. If you made a backup earlier, restore it
Check for one:
ls -t ~/.openclaw/openclaw.json.backup.* | head -1
If it exists, restore it:
cp "$(ls -t ~/.openclaw/openclaw.json.backup.* | head -1)" ~/.openclaw/openclaw.json
3. If you want to fully abandon the templating setup, move those helper files aside
mv ~/.openclaw/openclaw.template.json5 ~/.openclaw/openclaw.template.json5.disabled 2>/dev/null || true
mv ~/.openclaw/.env ~/.openclaw/.env.disabled 2>/dev/null || true
mv ~/.openclaw/secrets.json ~/.openclaw/secrets.json.disabled 2>/dev/null || true
4. Put a simple working Discord config directly in ~/.openclaw/openclaw.json
Use literal values, no templating:
{
channels: {
discord: {
enabled: true,
token: "YOUR_DISCORD_BOT_TOKEN",
groupPolicy: "allowlist",
guilds: {
"YOUR_SERVER_ID": {
requireMention: false,
users: ["YOUR_USER_ID"],
},
},
dmPolicy: "allowlist",
allowFrom: ["YOUR_USER_ID"],
dm: {
enabled: true,
},
},
},
}
5. Start it again
openclaw gateway start
openclaw gateway status
openclaw status