Skip to content

fix(discord): specify hydrated config for auto ack reactions to prevent SecretRef resolution failures#60081

Merged
steipete merged 4 commits intoopenclaw:mainfrom
FunJim:fix/discord-reaction-secret-ref
Apr 3, 2026
Merged

fix(discord): specify hydrated config for auto ack reactions to prevent SecretRef resolution failures#60081
steipete merged 4 commits intoopenclaw:mainfrom
FunJim:fix/discord-reaction-secret-ref

Conversation

@FunJim
Copy link
Copy Markdown
Contributor

@FunJim FunJim commented Apr 3, 2026

Fixes #57749

Background:
Automatic message reactions in Discord channels (ACK reactions) were silently failing to appear despite the manual CLI command (openclaw message react) succeeding perfectly.

Root Cause:
When the Discord webhook processor emits an ACK reaction, it triggers the callback setReaction and removeReaction inside extensions/discord/src/monitor/message-handler.process.ts. These methods delegate to reactMessageDiscord() and removeReactionDiscord().

However, they were omitting the cfg property in the options payload. Since the config dependency was omitted, the createDiscordRestClient function automatically retrieved the raw, unhydrated config from disk via loadConfig(). In deployments using secure SecretRef items (e.g. file:filemain:/channels/discord/token), it directly triggered an Error: channels.discord.token: unresolved SecretRef internally and aborted the request because it was actively trying to parse the literal URI string as a Discord application token instead of utilizing the hydrated RuntimeEnv object. In Multi-Account scenarios, it would resolve auth against the default account instead of the active account.

Fix:
This commit propagates the hydrated cfg (which contains decrypted variables globally validated by the runtime schema) from processDiscordMessage down to reactMessageDiscord and removeReactionDiscord. This bypasses the unhydrated loadConfig() fallback ensuring proper SecretRef parsing.

@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord size: XS labels Apr 3, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 3, 2026

Greptile Summary

This PR fixes silent failures in Discord auto-ACK reactions when using SecretRef-based token storage. The root cause was that reactMessageDiscord and removeReactionDiscord were called without a cfg argument, causing them to fall back to loadConfig() which returns unhydrated config — breaking SecretRef resolution at runtime.

Key changes:

  • Core fix: cfg is now passed to both reactMessageDiscord and removeReactionDiscord in the StatusReactionAdapter callbacks, using the already-hydrated config from processDiscordMessage's ctx. The DiscordReactOpts.cfg field and the opts.cfg ?? loadConfig() fallback in send.reactions.ts were already in place, so only the call-site was missing the value.
  • Diagnostic logging: Verbose process:start, process:setQueued, and process:setQueued-skipped log lines are added around the ACK-reaction path to aid future debugging.
  • Import ordering: resolveChunkMode and finalizeInboundContext imports are moved to their correct alphabetical position among the openclaw/plugin-sdk/reply-* imports.

Confidence Score: 4/5

Safe to merge — the fix is minimal, targeted, and uses existing typed plumbing that was already in place.

The change is a single-line fix per call-site that closes a clear SecretRef regression. The cfg field was already defined on DiscordReactOpts and the ?? loadConfig() fallback pattern in send.reactions.ts confirms the intended contract. New verbose logging follows established patterns and is guarded by shouldLogVerbose(). The only remark is cosmetic (cfg: cfg vs shorthand cfg). No logic or data-flow concerns.

No files require special attention beyond the cosmetic shorthand nit in extensions/discord/src/monitor/message-handler.process.ts.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/discord/src/monitor/message-handler.process.ts
Line: 201-210

Comment:
**Use ES6 shorthand property syntax for `cfg`**

`cfg: cfg` can be shortened to just `cfg` since the variable name matches the property name. The rest of the codebase (including `deliverDiscordReply` calls nearby) uses shorthand property syntax consistently.

```suggestion
      await reactMessageDiscord(messageChannelId, message.id, emoji, {
        rest: discordRest,
        cfg,
      });
```

Same applies to the `removeReaction` callback a few lines below:

```suggestion
      await removeReactionDiscord(messageChannelId, message.id, emoji, {
        rest: discordRest,
        cfg,
      });
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(discord): pass hydrated config to ac..." | Re-trigger Greptile

Comment thread extensions/discord/src/monitor/message-handler.process.ts
@FunJim FunJim force-pushed the fix/discord-reaction-secret-ref branch from 981da6d to d3822cf Compare April 3, 2026 05:03
@openclaw-barnacle openclaw-barnacle Bot added channel: whatsapp-web Channel integration: whatsapp-web and removed channel: whatsapp-web Channel integration: whatsapp-web labels Apr 3, 2026
@steipete steipete force-pushed the fix/discord-reaction-secret-ref branch from 99d6d78 to 2ceace5 Compare April 3, 2026 15:40
@steipete steipete requested a review from a team as a code owner April 3, 2026 15:40
@openclaw-barnacle openclaw-barnacle Bot added channel: telegram Channel integration: telegram agents Agent runtime and tooling size: S and removed size: XS labels Apr 3, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2ceace577d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 119 to +122
isTelegramExecApprovalAuthorizedSender({ cfg, accountId, senderId }) &&
!isTelegramExecApprovalApprover({ cfg, accountId, senderId })
) {
return { kind: "ignore" };
return undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Block /approve fallback when Telegram native approvals are off

Returning undefined in this branch re-enables normal /approve handling for senders who are authorized via isTelegramExecApprovalAuthorizedSender but are not approvers. In configs where channels.telegram.execApprovals.enabled is false but approval-target mode still marks the sender as authorized, handleApproveCommand will now fall through to gateway resolution and submit exec.approval.resolve instead of suppressing the command. This bypasses the channel-level disable behavior that was previously enforced by { kind: "ignore" } for this specific sender class.

Useful? React with 👍 / 👎.

@steipete steipete force-pushed the fix/discord-reaction-secret-ref branch from 2ceace5 to 46cc31b Compare April 3, 2026 15:48
@openclaw-barnacle openclaw-barnacle Bot removed the agents Agent runtime and tooling label Apr 3, 2026
FunJim and others added 4 commits April 4, 2026 00:50
…resolution

When extracting `reactMessageDiscord`, it defaulted to reading the raw config (which contains `SecretRef`s) if a hydrated `cfg` was omitted. We now pass the pre-resolved `cfg` context into the reaction options so the plugin SDK resolves the token via memory rather than the raw file.
The implementation fix propagates the hydrated cfg to reactMessageDiscord
and removeReactionDiscord. Update test assertions to expect the cfg
property in the options argument using expect.objectContaining to handle
the dynamic session store path.
@steipete steipete force-pushed the fix/discord-reaction-secret-ref branch from 46cc31b to 0fd5550 Compare April 3, 2026 15:53
@steipete steipete merged commit b7f524a into openclaw:main Apr 3, 2026
9 checks passed
@steipete
Copy link
Copy Markdown
Contributor

steipete commented Apr 3, 2026

Landed via temp rebase onto main.\n\n- Gate: pnpm check; pnpm build; pnpm test -- extensions/discord/src/monitor/message-handler.process.test.ts; pnpm test -- src/auto-reply/reply/commands.test.ts -t "accepts Telegram /approve from exec target recipients when native approvals are disabled"; pnpm test -- src/secrets/runtime.test.ts -t "skips inactive-surface refs and emits diagnostics"\n- Land commit: 0fd5550\n- Merge commit: b7f524a\n\nThanks @FunJim!

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0fd555094c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 119 to +122
isTelegramExecApprovalAuthorizedSender({ cfg, accountId, senderId }) &&
!isTelegramExecApprovalApprover({ cfg, accountId, senderId })
) {
return { kind: "ignore" };
return undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep /approve suppressed for non-approver Telegram targets

Returning undefined here makes /approve fall through to the generic handler when native Telegram exec approvals are disabled. In configs where a sender is authorized via exec approval targets but is not an approver, resolveApprovalCommandAuthorization can still treat exec approval as authorized, so the command may proceed to exec.approval.resolve instead of being suppressed, which bypasses the disabled-channel behavior that this branch previously enforced.

Useful? React with 👍 / 👎.

lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: discord Channel integration: discord channel: telegram Channel integration: telegram size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Discord reactions for non-default accounts resolve auth against 'default' account instead of active account

2 participants