openclaw - 💡(How to fix) Fix ackReactionScope: "all" is silently overridden by isRoomEvent gate

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…

channels.<provider>.ackReactionScope: "all" does not actually ack all inbound messages. A hardcoded !isRoomEvent gate in message-handler.process suppresses ack reactions for any inbound classified as room_event, even though the scope explicitly says "all".

This contradicts the schema description for ackReactionScope, which advertises "all" as unconditional.

Root Cause

dist/message-handler.process-LhrhAUW3.js:904-905:

const isRoomEvent = ctx.inboundEventKind === "room_event";
const shouldAckReaction$1 = () => Boolean(!isRoomEvent && ackReaction && shouldAckReaction({
  scope: ackReactionScope,
  isDirect: isDirectMessage,
  ...
}));

The !isRoomEvent short-circuit runs before shouldAckReaction(...), so scope: "all" never gets a chance to override it. The shouldAckReaction helper in ack-reactions.ts correctly returns true for scope "all", but the outer expression masks that.

Because messages.groupChat.unmentionedInbound: "room_event" is a legitimate, documented configuration (quiet always-on listening), inbound thread messages without an explicit @-mention are classified as room_event — and ack reactions get silently dropped.

Fix Action

Fix / Workaround

Workaround for users today

Code Example

"channels": {
     "discord": {
       "ackReaction": "✨",
       "accounts": { "samantha": { "ackReaction": "✨" } }
     }
   },
   "messages": {
     "ackReactionScope": "all",
     "groupChat": { "unmentionedInbound": "room_event" }
   }

---

const isRoomEvent = ctx.inboundEventKind === "room_event";
const shouldAckReaction$1 = () => Boolean(!isRoomEvent && ackReaction && shouldAckReaction({
  scope: ackReactionScope,
  isDirect: isDirectMessage,
  ...
}));

---

const isRoomEvent = ctx.inboundEventKind === "room_event";
const ackForcedAll = ackReactionScope === "all";
const shouldAckReaction$1 = () => Boolean((ackForcedAll || !isRoomEvent) && ackReaction && shouldAckReaction({ ... }));

---

"messages": {
  "ackReactionScope": "all",
  "ackReactionOnRoomEvent": true
}
RAW_BUFFERClick to expand / collapse

Summary

channels.<provider>.ackReactionScope: "all" does not actually ack all inbound messages. A hardcoded !isRoomEvent gate in message-handler.process suppresses ack reactions for any inbound classified as room_event, even though the scope explicitly says "all".

This contradicts the schema description for ackReactionScope, which advertises "all" as unconditional.

Version

OpenClaw 2026.5.26 (10ad3aa)

Repro

  1. Set Discord ack reaction config:
    "channels": {
      "discord": {
        "ackReaction": "✨",
        "accounts": { "samantha": { "ackReaction": "✨" } }
      }
    },
    "messages": {
      "ackReactionScope": "all",
      "groupChat": { "unmentionedInbound": "room_event" }
    }
  2. Restart gateway, confirm config applied via openclaw config get.
  3. Post a message in a guild thread/subthread where the bot is already participating, without @-mentioning the bot.
  4. Bot responds normally (autoThread context keeps the conversation alive).
  5. Expected: ack reaction () appears on the user's message.
  6. Actual: no reaction. messages.reactions is [] for the user message.

Manual reactions via message(action=reactionAdd) work fine — the issue is specifically the auto-ack code path.

Root cause

dist/message-handler.process-LhrhAUW3.js:904-905:

const isRoomEvent = ctx.inboundEventKind === "room_event";
const shouldAckReaction$1 = () => Boolean(!isRoomEvent && ackReaction && shouldAckReaction({
  scope: ackReactionScope,
  isDirect: isDirectMessage,
  ...
}));

The !isRoomEvent short-circuit runs before shouldAckReaction(...), so scope: "all" never gets a chance to override it. The shouldAckReaction helper in ack-reactions.ts correctly returns true for scope "all", but the outer expression masks that.

Because messages.groupChat.unmentionedInbound: "room_event" is a legitimate, documented configuration (quiet always-on listening), inbound thread messages without an explicit @-mention are classified as room_event — and ack reactions get silently dropped.

Why it matters

  • ackReactionScope schema help text says "all" = "always send the ack reaction" — users expect literally all messages.
  • Manual reactions work, so the bot clearly has permission and the emoji is valid; the suppression is purely in the gate logic.
  • There is no unmentionedInbound override at account / guild / channel level, so users can't selectively re-enable ack in a single thread.

Proposed fix

Two viable options:

Option A (preferred) — Make scope "all" truly bypass isRoomEvent:

const isRoomEvent = ctx.inboundEventKind === "room_event";
const ackForcedAll = ackReactionScope === "all";
const shouldAckReaction$1 = () => Boolean((ackForcedAll || !isRoomEvent) && ackReaction && shouldAckReaction({ ... }));

Option B — Add an explicit override flag:

"messages": {
  "ackReactionScope": "all",
  "ackReactionOnRoomEvent": true
}

Option A is cleaner since the contradiction is already in the doc/contract of "all".

Workaround for users today

@-mention the bot in the thread → classified as user_request → ack fires.

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