openclaw - ✅(Solved) Fix [Bug]: Discord DM react/reactions fail — channelId required but no DM channel id available in agent context [1 pull requests, 2 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#70165Fetched 2026-04-23 07:28:26
View on GitHub
Comments
2
Participants
2
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
commented ×2closed ×1cross-referenced ×1

Agents cannot react to Discord DMs on 2026.4.15. The message action=react and action=reactions handlers require a channelId resolved to channel:<id>, but in a Discord DM the agent only has access to user:<userId> from chat_id. There is no DM channel id exposed anywhere in inbound context, so the only allowed target kind is unobtainable.

Historically this worked — older session transcripts (2026.4.13 and earlier, Opus 4.6-1m) show successful DM react calls using just messageId with no channelId, returning {ok: true, added: "..."}. Somewhere between 4.13 and 4.15 the fallback path was lost and the requirement tightened.

Related: #29503 (closed, stale) — same symptom family, different root cause. PR #29739 (never merged) addressed missing message_id in DM inbound meta. message_id is now present in 4.15 — but the DM channel id is still not, which is the actual blocker for Discord reactions.

Error Message

Error: Discord channel id is required (use channel:<id>).

Root Cause

  • extensions/discord/api.(ts|js) react case:

    const resolveChannelId = () =>
      resolveDiscordChannelId(
        readStringParam(params, "channelId") ??
          readStringParam(params, "to", { required: true })
      );
  • resolveDiscordChannelId hard-requires a channel-kind target via requireTargetKind

  • inbound_meta.v2 exposes chat_id for DMs as user:<id>, not channel:<id>, and no DM channel id is cached or surfaced elsewhere for the agent to read

  • sendMessage (Discord plugin) already handles user: targets correctly by calling resolveChannelId from send.shared — which does POST /users/@me/channels { recipient_id } via the REST client. The react/reactions path just doesn't reuse that logic.

Fix Action

Fix / Workaround

Verified locally by patching the bundled dist/extensions/discord/api.js on 2026.4.15: DM reactions now succeed with just messageId (no channelId passed), returning {ok: true, added: "🥕"}. No behavior change for channel-kind targets. Monkey-patch diff posted as a comment below for anyone hitting this before an upstream fix lands.

PR fix notes

PR #70314: fix(discord): restore DM reactions and guild activation

Description (problem / solution / changelog)

Summary

  • let Discord message tool reactions resolve user:<id> DM targets through the existing DM-channel creation path
  • use the current Discord conversation target for reaction actions when the agent reacts to the inbound message without an explicit target
  • preserve Discord guild/channel requireMention: false during reply-stage activation fallback when the plugin resolver is unavailable

Fixes #70165. Fixes #69441.

Tests

  • pnpm test extensions/discord/src/actions/handle-action.test.ts extensions/discord/src/actions/runtime.test.ts extensions/discord/src/send.sends-basic-channel-messages.test.ts src/auto-reply/reply/groups.test.ts
  • pnpm check:changed
  • pnpm check
  • pnpm build
  • pnpm test attempted full suite. Touched shards passed; full suite hit unrelated persistent extensions/openai/provider-runtime.contract.test.ts failure: Failed to refresh OpenAI Codex token in owns refresh fallback for accountId extraction failures. Exact rerun of that test still fails on this checkout. Two other full-suite failures (src/agents/subagent-registry.persistence.resume.test.ts, src/gateway/server-startup.test.ts) passed on exact rerun.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/discord/src/actions/handle-action.test.ts (modified, +49/-0)
  • extensions/discord/src/actions/handle-action.ts (modified, +24/-6)
  • extensions/discord/src/actions/runtime.messaging.ts (modified, +34/-3)
  • extensions/discord/src/actions/runtime.test.ts (modified, +51/-0)
  • extensions/discord/src/recipient-resolution.ts (modified, +5/-2)
  • extensions/discord/src/send.sends-basic-channel-messages.test.ts (modified, +35/-0)
  • extensions/discord/src/send.shared.ts (modified, +16/-2)
  • src/auto-reply/reply/groups.test.ts (modified, +83/-0)
  • src/auto-reply/reply/groups.ts (modified, +115/-0)

Code Example

message(action="react", emoji="👌", messageId="<inbound_message_id>")

---

Error: Discord channel id is required (use channel:<id>).

---

const resolveChannelId = () =>
    resolveDiscordChannelId(
      readStringParam(params, "channelId") ??
        readStringParam(params, "to", { required: true })
    );

---

async function resolveChannelIdForReaction(params, cfg, accountId) {
  const rawTarget =
    readStringParam(params, "channelId") ??
    readStringParam(params, "to", { required: true });
  const parsed = parseDiscordTarget(rawTarget, { defaultKind: "channel" });
  if (parsed && parsed.kind === "user") {
    const opts = { cfg, accountId };
    const { rest, request } = createDiscordClient(opts, cfg);
    const recipient = await parseAndResolveRecipient(rawTarget, accountId, cfg);
    const resolved = await resolveChannelId(rest, recipient, request);
    return "channel:" + resolved.channelId;
  }
  return resolveDiscordChannelId(rawTarget);
}
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

Agents cannot react to Discord DMs on 2026.4.15. The message action=react and action=reactions handlers require a channelId resolved to channel:<id>, but in a Discord DM the agent only has access to user:<userId> from chat_id. There is no DM channel id exposed anywhere in inbound context, so the only allowed target kind is unobtainable.

Historically this worked — older session transcripts (2026.4.13 and earlier, Opus 4.6-1m) show successful DM react calls using just messageId with no channelId, returning {ok: true, added: "..."}. Somewhere between 4.13 and 4.15 the fallback path was lost and the requirement tightened.

Related: #29503 (closed, stale) — same symptom family, different root cause. PR #29739 (never merged) addressed missing message_id in DM inbound meta. message_id is now present in 4.15 — but the DM channel id is still not, which is the actual blocker for Discord reactions.

Steps to reproduce

  1. Send the bot a Discord DM

  2. From the agent, call:

    message(action="react", emoji="👌", messageId="<inbound_message_id>")
  3. Observe error

Passing target: "user:<userId>" (the value from inbound chat_id) also fails because resolveDiscordChannelId only accepts kind === "channel".

Expected behavior

React/reactions should accept user:<id> targets (or fall back to resolving the DM channel from messageId / inbound context) and work in DMs, matching the behavior of sendMessage which already handles user: targets correctly by creating/fetching the DM channel via POST /users/@me/channels.

Result should be {ok: true, added: "<emoji>"} with the reaction visible in the Discord client.

Actual behavior

Error: Discord channel id is required (use channel:<id>).

Reproducible on every Discord DM react attempt.

Root cause

  • extensions/discord/api.(ts|js) react case:

    const resolveChannelId = () =>
      resolveDiscordChannelId(
        readStringParam(params, "channelId") ??
          readStringParam(params, "to", { required: true })
      );
  • resolveDiscordChannelId hard-requires a channel-kind target via requireTargetKind

  • inbound_meta.v2 exposes chat_id for DMs as user:<id>, not channel:<id>, and no DM channel id is cached or surfaced elsewhere for the agent to read

  • sendMessage (Discord plugin) already handles user: targets correctly by calling resolveChannelId from send.shared — which does POST /users/@me/channels { recipient_id } via the REST client. The react/reactions path just doesn't reuse that logic.

Proposed fix (minimal)

Inside extensions/discord/api react/reactions handlers, reuse the existing DM channel resolution helpers from the Discord plugin's own send path:

async function resolveChannelIdForReaction(params, cfg, accountId) {
  const rawTarget =
    readStringParam(params, "channelId") ??
    readStringParam(params, "to", { required: true });
  const parsed = parseDiscordTarget(rawTarget, { defaultKind: "channel" });
  if (parsed && parsed.kind === "user") {
    const opts = { cfg, accountId };
    const { rest, request } = createDiscordClient(opts, cfg);
    const recipient = await parseAndResolveRecipient(rawTarget, accountId, cfg);
    const resolved = await resolveChannelId(rest, recipient, request);
    return "channel:" + resolved.channelId;
  }
  return resolveDiscordChannelId(rawTarget);
}

Call it from the react and reactions cases instead of the current sync resolveChannelId(). Both actions already await downstream calls, so making this async is a no-op to the signature.

Verified locally by patching the bundled dist/extensions/discord/api.js on 2026.4.15: DM reactions now succeed with just messageId (no channelId passed), returning {ok: true, added: "🥕"}. No behavior change for channel-kind targets. Monkey-patch diff posted as a comment below for anyone hitting this before an upstream fix lands.

Happy to open a PR against main if the approach is acceptable.

OpenClaw version

2026.4.15 (commit 041266a)

Operating system

Linux (Ubuntu, kernel 6.17.0-20-generic, x64)

Install method

npm (global, ~/.npm-global/lib/node_modules/openclaw)

extent analysis

TL;DR

The most likely fix is to modify the resolveChannelId function in extensions/discord/api to reuse the existing DM channel resolution helpers from the Discord plugin's send path.

Guidance

  • Identify the resolveChannelId function in extensions/discord/api and modify it to handle user: targets by resolving the DM channel using the resolveChannelIdForReaction function.
  • Verify that the resolveChannelIdForReaction function is correctly resolving the DM channel by checking the resolved.channelId value.
  • Update the react and reactions cases to use the modified resolveChannelId function.
  • Test the changes by sending a Discord DM and attempting to react to it using the message action.

Example

async function resolveChannelIdForReaction(params, cfg, accountId) {
  // ...
}

// Call the modified function from the react and reactions cases
const channelId = await resolveChannelIdForReaction(params, cfg, accountId);

Notes

  • The proposed fix assumes that the resolveChannelIdForReaction function is correctly implemented and resolves the DM channel correctly.
  • The fix may require additional modifications to handle edge cases or errors.

Recommendation

Apply the proposed workaround by modifying the resolveChannelId function to reuse the existing DM channel resolution helpers from the Discord plugin's send path, as it has been verified to work locally and does not introduce any new dependencies or breaking changes.

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

React/reactions should accept user:<id> targets (or fall back to resolving the DM channel from messageId / inbound context) and work in DMs, matching the behavior of sendMessage which already handles user: targets correctly by creating/fetching the DM channel via POST /users/@me/channels.

Result should be {ok: true, added: "<emoji>"} with the reaction visible in the Discord client.

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 DM react/reactions fail — channelId required but no DM channel id available in agent context [1 pull requests, 2 comments, 2 participants]