openclaw - ✅(Solved) Fix [Bug]: Discord `message read/search` hang indefinitely and Discord channel plugin does not emit standard inbound hooks (`message_received` / `inbound_claim`) — possible regression of #31264 / #33038 [2 pull requests, 1 comments, 2 participants]

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…
GitHub stats
openclaw/openclaw#73431Fetched 2026-04-29 06:19:59
View on GitHub
Comments
1
Participants
2
Timeline
9
Reactions
0
Author
Timeline (top)
cross-referenced ×3labeled ×2referenced ×2closed ×1

On OpenClaw 2026.4.25, Discord message read and message search hang indefinitely with empty stdout, and the Discord channel plugin does not appear to emit the standard inbound hooks (message_received / inbound_claim) that other channels expose. This appears to be a regression or incomplete coverage of the prior fix discussed in #31212 / #31264 / #33038.

Error Message

  1. Observe that the command hangs indefinitely with empty stdout (no JSON returned, no explicit error).
  • The command should either return a JSON payload of messages, or fail fast with a structured error.
  1. openclaw message read --channel discord --target <channelId> --limit 1 --json hangs indefinitely. After 20s+ external timeout, stdout remains empty and no JSON or structured error is returned. Only generic startup lines appear on stderr (config warnings, plugin command registrations).

Root Cause

On OpenClaw 2026.4.25, Discord message read and message search hang indefinitely with empty stdout, and the Discord channel plugin does not appear to emit the standard inbound hooks (message_received / inbound_claim) that other channels expose. This appears to be a regression or incomplete coverage of the prior fix discussed in #31212 / #31264 / #33038.

Fix Action

Fix / Workaround

  1. Install OpenClaw 2026.4.25 on macOS, with the Discord plugin enabled and a bot token configured for at least one guild.

  2. Pair the local CLI device successfully (openclaw devices list --json shows the device with operator scopes).

  3. Run: openclaw message read --channel discord --target <channelId> --limit 1 --json

  4. Observe that the command hangs indefinitely with empty stdout (no JSON returned, no explicit error).

  5. Run: openclaw message search --channel discord --guild-id <guildId> --channel-id <channelId> --query test --limit 1 --json

  6. Observe the same hanging behavior.

  7. Inspect the bundled Discord plugin code under dist/extensions/discord/ and the dispatch code under dist/dispatch-*.js. Observe that the Discord plugin has internal listener and processing code (DiscordMessageListener, processDiscordMessage) but no equivalent calls to runMessageReceived(...) or triggerInternalHook(createInternalHookEvent("message", "received", ...)) that other channels emit.

  8. Compare release tag source v2026.4.25 and v2026.4.26 against the fallback logic proposed in PR #33038. Observe that the proposed fallback is not present in the current release line.

  9. Source inspection of v2026.4.25 and v2026.4.26 shows that the fallback logic proposed in PR #33038 (ctx.SessionKey?.trim() || ctx.CommandTargetSessionKey?.trim() || undefined in dispatch-from-config.ts, and the inboundSessionKey array in extensions/discord/src/monitor/message-handler.process.ts) is not present in the release source.

  10. The bundled Discord extension contains internal listener and processing logic but does not appear to emit runMessageReceived(...) / toPluginMessageReceivedEvent(...) / triggerInternalHook(createInternalHookEvent("message", "received", ...)) the way other channel paths do in dist/dispatch-*.js.

PR fix notes

PR #73504: fix(discord): route message actions to gateway to fix CLI read/search hang

Description (problem / solution / changelog)

Summary

Fixes #73431 — openclaw message read --channel discord and openclaw message search --channel discord hang indefinitely in CLI mode.

Root Cause

Discord's channel action adapter did not define resolveExecutionMode, so it defaulted to "local". When the CLI invokes a message action, the execution mode determines whether the action is forwarded to the gateway (where the Discord bot runtime lives) or executed in-process.

With "local" mode, the CLI attempts to execute Discord REST calls directly. However, in CLI context the Discord bot client/runtime is not initialized — the bot runs exclusively in the gateway process. This causes the action to hang indefinitely waiting for a runtime that will never be available.

Other channels like Telegram correctly return "gateway" from resolveExecutionMode, so the CLI forwards the action to the gateway via callGatewayMessageAction, which then dispatches it locally where the bot runtime is active.

Fix

Add resolveExecutionMode: () => "gateway" to Discord's discordMessageActions adapter (in channel-actions.ts) and forward it through the wrapper in channel.ts.

Regarding inbound hooks (message_received / inbound_claim)

The issue also asks about missing hook emissions. After code inspection, Discord inbound messages do fire message_received and triggerInternalHook hooks — they are emitted by the generic dispatchReplyFromConfig path (lines 702–725 of src/auto-reply/reply/dispatch-from-config.ts), which Discord reaches via dispatchInboundMessage in message-handler.process.ts. The hookCount: 0 in plugins list output reflects that the Discord plugin itself does not register any hooks (it is a channel provider, not a hook consumer) — this is correct behavior.

Verification

  • No pnpm available locally; typecheck and tests cannot be run.
  • Verified via code inspection that the fix matches the Telegram pattern exactly.
  • The change is minimal (2 insertions) and cannot regress: it only affects the CLI→gateway routing decision for Discord actions.

Changed files

  • extensions/discord/src/channel-actions.ts (modified, +1/-0)
  • extensions/discord/src/channel.ts (modified, +1/-0)

PR #73521: fix: Discord read/search timeout, session-key fallback, and gateway execution mode

Description (problem / solution / changelog)

Summary

Fixes #73431 — Discord message read and message search hang indefinitely, and Discord inbound message_received / inbound_claim hooks do not fire when SessionKey is empty.

Three targeted fixes, no feature creep:

1. REST timeout on Discord read/search (extensions/discord/src/send.messages.ts)

readMessagesDiscord and searchMessagesDiscord awaited rest.get(...) with no timeout or abort signal. If the Discord API hung or was slow, the CLI hung forever with empty stdout.

Added a 15-second withRestTimeout wrapper that races the promise against a timer and rejects with a structured error message.

2. Session-key fallback for inbound hooks (src/auto-reply/reply/dispatch-from-config.ts)

The internal message:received hook (line 722) is gated on sessionKey being truthy. The session key was read as ctx.SessionKey with no fallback — but Discord's SessionKey derivation can yield empty in edge cases (DMs, misconfigured channels, missing thread context).

Now falls back to ctx.CommandTargetSessionKey via normalizeOptionalString, matching the pattern already used by resolveSessionStoreLookup in the same file. This restores the intent of the closed-but-never-landed PR #33038.

3. resolveExecutionMode on Discord channel actions (extensions/discord/src/channel-actions.ts)

Discord did not define resolveExecutionMode, so all actions defaulted to "local" execution — bypassing the gateway's 10-second action timeout that Telegram gets automatically. Now routes read and search through "gateway" mode for defense-in-depth.

Testing

  • New test file extensions/discord/src/send.messages.test.ts — verifies timeout behavior for both read and search (happy path + hang rejection)
  • New tests in extensions/discord/src/channel-actions.test.ts — verifies resolveExecutionMode returns "gateway" for read/search, "local" for other actions
  • New test in src/auto-reply/reply/dispatch-from-config.test.ts — verifies CommandTargetSessionKey fallback fires the internal hook when SessionKey is empty
  • All existing tests continue to pass (218 tests across 7 files, 0 failures)
  • pnpm check:changed passes all lanes (typecheck, lint, import cycles, guards)
  • No live Discord verification (no credentials in this environment), but the timeout and hook fixes are unit-tested against the exact failure modes described in #73431

Diff stats

5 files changed, 72 insertions(+), 3 deletions(-)

Supersedes the approach in #61572 which added ~1000 lines of tangential feature work (compact/raw detail modes, breaking legacy parameter changes) without addressing either root cause.

Changed files

  • extensions/discord/src/channel-actions.test.ts (modified, +15/-0)
  • extensions/discord/src/channel-actions.ts (modified, +2/-0)
  • extensions/discord/src/proxy-request-client.test.ts (added, +66/-0)
  • extensions/discord/src/proxy-request-client.ts (modified, +5/-1)
  • extensions/discord/src/send.messages.test.ts (added, +53/-0)
  • src/auto-reply/reply/dispatch-from-config.test.ts (modified, +28/-0)
  • src/auto-reply/reply/dispatch-from-config.ts (modified, +2/-1)

Code Example

Timed wrapper output for `message read` (typical):
ELAPSED_SEC: 20.008
TIMEOUT_SEC: 20
STDOUT<



STDOUT
STDERR<
Config warnings:




plugins.entries.whatsapp: plugin disabled (disabled in config) but config is present




STDERR




Discord plugin status from `plugins list --json`:


{
  "id": "discord",
  "name": "@openclaw/discord",
  "version": "2026.4.25",
  "format": "openclaw",
  "enabled": true,
  "status": "loaded",
  "channelIds": ["discord"],
  "httpRoutes": 0,
  "hookCount": 0
}


Code references inspected in the local install at `/Users/<user>/.npm-global/lib/node_modules/openclaw/dist/`:

- `dist/extensions/discord/provider-C7FYFXVp.js` — contains `DiscordMessageListener`, `registerDiscordMonitorListeners(...)`, `registerDiscordListener(...)`
- `dist/extensions/discord/message-handler.process-TPiKFEKP.js` — contains `processDiscordMessage(...)`
- `dist/extensions/discord/send-C5KMi0rM.js` — contains `readMessagesDiscord(...)` and `searchMessagesDiscord(...)` (REST implementations exist)
- `dist/dispatch-CerU5CEB.js` — contains generic `runMessageReceived(...)`, `toPluginMessageReceivedEvent(...)`, `triggerInternalHook(createInternalHookEvent("message", "received", ...))` for non-Discord paths
- `dist/plugin-sdk/src/plugins/hook-types.d.ts` — declares `message_received` and `inbound_claim` hooks

I could not find equivalent calls to those hook emissions inside the Discord extension files.

Verification against release tag sources:
- The fallback logic proposed in PR #33038 (`ctx.SessionKey?.trim() || ctx.CommandTargetSessionKey?.trim() || undefined`) is not present in `v2026.4.25` or `v2026.4.26` in `src/auto-reply/reply/dispatch-from-config.ts`.
- The `inboundSessionKey` construction proposed in PR #33038 is not present in `v2026.4.25` or `v2026.4.26` in `extensions/discord/src/monitor/message-handler.process.ts`.
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

On OpenClaw 2026.4.25, Discord message read and message search hang indefinitely with empty stdout, and the Discord channel plugin does not appear to emit the standard inbound hooks (message_received / inbound_claim) that other channels expose. This appears to be a regression or incomplete coverage of the prior fix discussed in #31212 / #31264 / #33038.

Steps to reproduce

  1. Install OpenClaw 2026.4.25 on macOS, with the Discord plugin enabled and a bot token configured for at least one guild.
  2. Pair the local CLI device successfully (openclaw devices list --json shows the device with operator scopes).
  3. Run: openclaw message read --channel discord --target <channelId> --limit 1 --json
  4. Observe that the command hangs indefinitely with empty stdout (no JSON returned, no explicit error).
  5. Run: openclaw message search --channel discord --guild-id <guildId> --channel-id <channelId> --query test --limit 1 --json
  6. Observe the same hanging behavior.
  7. Inspect the bundled Discord plugin code under dist/extensions/discord/ and the dispatch code under dist/dispatch-*.js. Observe that the Discord plugin has internal listener and processing code (DiscordMessageListener, processDiscordMessage) but no equivalent calls to runMessageReceived(...) or triggerInternalHook(createInternalHookEvent("message", "received", ...)) that other channels emit.
  8. Compare release tag source v2026.4.25 and v2026.4.26 against the fallback logic proposed in PR #33038. Observe that the proposed fallback is not present in the current release line.

Expected behavior

For message read and message search:

  • The command should either return a JSON payload of messages, or fail fast with a structured error.
  • It should not hang indefinitely with empty stdout.

For Discord inbound hooks:

  • Discord inbound messages should expose the standard inbound hook surface (message_received / inbound_claim) consistently with other channels (Telegram, WhatsApp, Signal), so that plugin authors and integrations can build push/event-driven workflows on top of Discord the same way they can with other channels.

Reference: PR #33038 was closed by a maintainer with the comment Superceded by existing commits on main, suggesting that this area was meant to be fixed on main. The current observable behavior on v2026.4.25 suggests the fix is either absent from the release, partial, or has regressed.

Actual behavior

  1. openclaw message read --channel discord --target <channelId> --limit 1 --json hangs indefinitely. After 20s+ external timeout, stdout remains empty and no JSON or structured error is returned. Only generic startup lines appear on stderr (config warnings, plugin command registrations).

  2. openclaw message search --channel discord --guild-id <guildId> --channel-id <channelId> --query <term> --limit 1 --json hangs in the same way.

  3. Re-pairing the local CLI device with widened operator scopes (operator.admin, operator.read, operator.write, operator.approvals, operator.pairing, operator.talk.secrets) does not change the behavior. The hang persists.

  4. The Discord plugin reports as loaded and enabled in openclaw plugins list --json. The bot is otherwise active in Discord channels.

  5. Source inspection of v2026.4.25 and v2026.4.26 shows that the fallback logic proposed in PR #33038 (ctx.SessionKey?.trim() || ctx.CommandTargetSessionKey?.trim() || undefined in dispatch-from-config.ts, and the inboundSessionKey array in extensions/discord/src/monitor/message-handler.process.ts) is not present in the release source.

  6. The bundled Discord extension contains internal listener and processing logic but does not appear to emit runMessageReceived(...) / toPluginMessageReceivedEvent(...) / triggerInternalHook(createInternalHookEvent("message", "received", ...)) the way other channel paths do in dist/dispatch-*.js.

OpenClaw version

2026.4.25

Operating system

macOS 26.4.1 (Darwin 25.4.0, arm64)

Install method

npm global

Model

openai-codex/gpt-5.4

Provider / routing chain

NOT_ENOUGH_INFO

Additional provider/model setup details

The agent gateway uses model openai-codex/gpt-5.4. This bug is not related to model behavior — the failure is in the OpenClaw CLI / gateway / Discord plugin path, not in the LLM. The model field is included for completeness as the template requests it.

Logs, screenshots, and evidence

Timed wrapper output for `message read` (typical):
ELAPSED_SEC: 20.008
TIMEOUT_SEC: 20
STDOUT<



STDOUT
STDERR<
Config warnings:




plugins.entries.whatsapp: plugin disabled (disabled in config) but config is present




STDERR




Discord plugin status from `plugins list --json`:


{
  "id": "discord",
  "name": "@openclaw/discord",
  "version": "2026.4.25",
  "format": "openclaw",
  "enabled": true,
  "status": "loaded",
  "channelIds": ["discord"],
  "httpRoutes": 0,
  "hookCount": 0
}


Code references inspected in the local install at `/Users/<user>/.npm-global/lib/node_modules/openclaw/dist/`:

- `dist/extensions/discord/provider-C7FYFXVp.js` — contains `DiscordMessageListener`, `registerDiscordMonitorListeners(...)`, `registerDiscordListener(...)`
- `dist/extensions/discord/message-handler.process-TPiKFEKP.js` — contains `processDiscordMessage(...)`
- `dist/extensions/discord/send-C5KMi0rM.js` — contains `readMessagesDiscord(...)` and `searchMessagesDiscord(...)` (REST implementations exist)
- `dist/dispatch-CerU5CEB.js` — contains generic `runMessageReceived(...)`, `toPluginMessageReceivedEvent(...)`, `triggerInternalHook(createInternalHookEvent("message", "received", ...))` for non-Discord paths
- `dist/plugin-sdk/src/plugins/hook-types.d.ts` — declares `message_received` and `inbound_claim` hooks

I could not find equivalent calls to those hook emissions inside the Discord extension files.

Verification against release tag sources:
- The fallback logic proposed in PR #33038 (`ctx.SessionKey?.trim() || ctx.CommandTargetSessionKey?.trim() || undefined`) is not present in `v2026.4.25` or `v2026.4.26` in `src/auto-reply/reply/dispatch-from-config.ts`.
- The `inboundSessionKey` construction proposed in PR #33038 is not present in `v2026.4.25` or `v2026.4.26` in `extensions/discord/src/monitor/message-handler.process.ts`.

Impact and severity

Affected: Any integration on top of OpenClaw 2026.4.25 that needs to read Discord channel history via openclaw message read / openclaw message search, or that needs to consume Discord inbound messages through the standard hook surface (message_received / inbound_claim).

Severity: High for Discord-based workflows. Discord becomes the only channel where neither historical fetch nor push/event-driven integrations work reliably, while Telegram / WhatsApp / Signal continue to work.

Frequency: Always. Every invocation of message read and message search on Discord hangs. Every attempt to subscribe to Discord inbound via the standard hook surface receives nothing.

Consequence: Plugin authors and integrators cannot build Discord ingest into agent queues, dashboards, or external automation systems using the documented surface. Workarounds require either patching the Discord plugin or using a separate Discord client outside OpenClaw.

Additional information

Related prior history that suggests this is a regression or incomplete coverage of an earlier fix:

  • #31212 — message:received hook does not fire for Discord guild channel messages — closed as not planned due to inactivity (auto-closed by stale bot)
  • #31264 — Discord: guard message:received hook session keys — closed as superseded by #33038
  • #33038 — Discord: guard message:received hook session keys — closed by maintainer with comment Superceded by existing commits on main

I checked the source of v2026.4.25 and v2026.4.26 and the specific guards proposed in #33038 are not present. This is what motivates the "regression or incomplete coverage" framing rather than a fresh feature request.

Adjacent open issues for context (not duplicates):

  • #71546 — Discord ingest lag of 100–400 s on stable connection persists after PR #68159 / 2026.4.1 reconnect-ownership change
  • #71948 — Discord inbound worker repeatedly times out after 1800s while gateway is still running
  • #61572 — Harden Discord reads and message targeting (open PR)

Last known reference of the proposed fix being acknowledged: 2026-03-03 (maintainer comment on #33038). First version where the current observable symptoms were verified by me: 2026.4.25.

Questions for maintainers:

  1. Is the March fix discussed in #31264 / #33038 actually present in the current release line, or did it never ship?
  2. If it is supposed to be present, why do these symptoms persist (message read/search hang and missing inbound hook emission for Discord)?
  3. Is the absence of the runMessageReceived(...) / triggerInternalHook(...) call path inside the Discord extension intentional design, or an oversight relative to other channels?

extent analysis

TL;DR

The most likely fix involves applying the fallback logic proposed in PR #33038 to the Discord plugin, ensuring that message_received and inbound_claim hooks are emitted consistently with other channels.

Guidance

  1. Verify the absence of the fallback logic: Confirm that the proposed logic in PR #33038 is not present in the current release (v2026.4.25 and v2026.4.26) by inspecting dispatch-from-config.ts and message-handler.process.ts.
  2. Check for intentional design or oversight: Investigate whether the absence of runMessageReceived(...) and triggerInternalHook(...) calls in the Discord extension is an intentional design choice or an oversight compared to other channels.
  3. Apply the proposed fallback logic: If the logic is not present, apply the proposed changes from PR #33038 to the Discord plugin to enable the emission of message_received and inbound_claim hooks.
  4. Test the fix: After applying the changes, test the openclaw message read and openclaw message search commands to ensure they no longer hang indefinitely and that the standard inbound hooks are emitted for Discord.

Example

No code snippet is provided as the issue requires verification and potential application of existing proposed fixes rather than introducing new code.

Notes

The solution assumes that the proposed fallback logic in PR #33038 is correct and applicable to the current release. If the logic is incomplete or incorrect, further investigation and adjustments may be necessary.

Recommendation

Apply the workaround by implementing the proposed fallback logic from PR #33038 to the Discord plugin, as it appears to address the regression or incomplete coverage of the earlier fix. This should enable the consistent emission of message_received and inbound_claim hooks for Discord, aligning with the behavior of other channels.

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…

FAQ

Expected behavior

For message read and message search:

  • The command should either return a JSON payload of messages, or fail fast with a structured error.
  • It should not hang indefinitely with empty stdout.

For Discord inbound hooks:

  • Discord inbound messages should expose the standard inbound hook surface (message_received / inbound_claim) consistently with other channels (Telegram, WhatsApp, Signal), so that plugin authors and integrations can build push/event-driven workflows on top of Discord the same way they can with other channels.

Reference: PR #33038 was closed by a maintainer with the comment Superceded by existing commits on main, suggesting that this area was meant to be fixed on main. The current observable behavior on v2026.4.25 suggests the fix is either absent from the release, partial, or has regressed.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: Discord `message read/search` hang indefinitely and Discord channel plugin does not emit standard inbound hooks (`message_received` / `inbound_claim`) — possible regression of #31264 / #33038 [2 pull requests, 1 comments, 2 participants]