hermes - 💡(How to fix) Fix [Bug]: claw migrate emits "*" wildcard in DISCORD_ALLOWED_USERS but _is_allowed_user does not honor it, blocking all non-self users

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

After migrating from OpenClaw, a Discord bot that previously ran on a public server (i.e. with allowFrom: ["*"] permitting any user) silently stops responding to anyone other than the owner. There's no log line, no error, no slash-command feedback — the bot simply ignores everyone except the IDs that came across literally. The migrator preserves the source list (DISCORD_ALLOWED_USERS=<id>,*), but the consumer-side allowlist check on Discord doesn't recognise the "*" entry as "open mode", even though that is the documented convention used by SIGNAL_ALLOWED_USERS and by the Discord channel-scope envs.

Additional Logs / Traceback (optional)

Root Cause

The bot processes the message, because "*" was in the source allowFrom list and the documented Signal-side semantic is that "*" means "open mode". _is_allowed_user should short-circuit True whenever "*" in _allowed_user_ids.

Fix Action

Fix / Workaround

PR with a 6-line patch + 3 unit tests is filed alongside this issue (DM path, channel path, and mixed <id>,* form — the literal output of claw migrate).

Code Example

"channels": {
     "discord": {
       "accounts": {
         "side-pub": {
           "token": "<bot-token>",
           "allowFrom": ["123456789012345678", "*"]
         }
       }
     }
   }

---

adapter._allowed_user_ids = {"123456789012345678", "*"}
adapter._is_allowed_user("42")                                                                                          
# returns False on current main; expected True

---

Report      https://paste.rs/t15sP
agent.log   https://paste.rs/vYrik
gateway.log https://paste.rs/mEjJW

---
RAW_BUFFERClick to expand / collapse

Bug Description

After migrating from OpenClaw, a Discord bot that previously ran on a public server (i.e. with allowFrom: ["*"] permitting any user) silently stops responding to anyone other than the owner. There's no log line, no error, no slash-command feedback — the bot simply ignores everyone except the IDs that came across literally. The migrator preserves the source list (DISCORD_ALLOWED_USERS=<id>,*), but the consumer-side allowlist check on Discord doesn't recognise the "*" entry as "open mode", even though that is the documented convention used by SIGNAL_ALLOWED_USERS and by the Discord channel-scope envs.

Steps to Reproduce

  1. Start with an OpenClaw install whose ~/.openclaw/openclaw.json contains
    "channels": {
      "discord": {
        "accounts": {
          "side-pub": {
            "token": "<bot-token>",
            "allowFrom": ["123456789012345678", "*"]
          }
        }
      }
    }
  2. Run hermes claw migrate --preset full --migrate-secrets --workspace-target ~/.hermes/profiles/side-pub/workspace
  3. Inspect the generated ~/.hermes/profiles/side-pub/.env — it contains DISCORD_ALLOWED_USERS=123456789012345678,*
  4. Start the gateway: hermes --profile side-pub gateway run
  5. Have a Discord user other than 123456789012345678 @-mention the bot in a guild channel.

Expected Behavior

The bot processes the message, because "*" was in the source allowFrom list and the documented Signal-side semantic is that "*" means "open mode". _is_allowed_user should short-circuit True whenever "*" in _allowed_user_ids.

Actual Behavior

on_message enters the non-bot branch, calls _is_allowed_user, the set-membership check returns False (because "*" is just a literal string in the set, not a wildcard), and the handler returns silently. No log line, no Discord interaction.

Direct verification via the existing test scaffold:

adapter._allowed_user_ids = {"123456789012345678", "*"}
adapter._is_allowed_user("42")                                                                                          
# returns False on current main; expected True

The same gate is reached from _check_slash_authorization (per code reading; _is_allowed_user is invoked from the slash-auth path), so slash commands are likely affected the same way — I didn't directly verify the slash path.

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

Messaging Platform (if gateway-related)

Discord

Debug Report

Report      https://paste.rs/t15sP
agent.log   https://paste.rs/vYrik
gateway.log https://paste.rs/mEjJW

Operating System

Ubuntu 24.04 (Linux 6.17, x86_64)

Python Version

3.11.15

Hermes Version

0.13.0 (2026.5.7) — verified bug still present on upstream main at a7e7921db after hermes update

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

DiscordAdapter._is_allowed_user (gateway/platforms/discord.py:2156-2256, key gating check at line 2193) checks user_id in self._allowed_user_ids directly, with no special-case for the "*" literal that other allowlists in the same codebase already treat as an open-mode wildcard:

Env / configFile:lineHonors "*"?
SIGNAL_ALLOWED_USERSsignal.py:199-201, 1456yes — documented in source comments
signal.py group allowlistsignal.py:505yes
DISCORD_ALLOWED_CHANNELSdiscord.py:4084yes
DISCORD_IGNORED_CHANNELSdiscord.py:2323, 4091yes
DISCORD_FREE_RESPONSE_CHANNELSdiscord.py:782, 4106yes
DISCORD_ALLOWED_USERSdiscord.py:_is_allowed_user 2156-2256 (line 2193)no — this is the gap

_clean_discord_id("*") returns "*" unchanged (discord.py:71-85), so the literal survives parsing and lands in the set as a string member that nothing ever matches against.

Proposed Fix (optional)

Short-circuit _is_allowed_user to True when "*" is present in _allowed_user_ids, so Discord's user allowlist matches the convention already used by Signal's user allowlist and Discord's channel allowlists.

PR with a 6-line patch + 3 unit tests is filed alongside this issue (DM path, channel path, and mixed <id>,* form — the literal output of claw migrate).

Scope notes:

  • Discord only. Slack / WhatsApp / Telegram / Matrix / Mattermost / MSTeams take the same allowFrom → *_ALLOWED_USERS translation in openclaw_to_hermes.py:1432, 1453, 1468, 1489, 2589. Whether each consumer-side check honors "*" deserves an audit as follow-up; Signal already does, the others I haven't checked.
  • DISCORD_ALLOWED_ROLES wildcard is intentionally out of scope — role IDs are integers and admitting "*" would need a separate design call, not blocking this regression.

Related migration-side issue: #18097 (different sub-bug — WhatsApp channel block dropped during migrate).

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix [Bug]: claw migrate emits "*" wildcard in DISCORD_ALLOWED_USERS but _is_allowed_user does not honor it, blocking all non-self users