← Back to PRs

#20009: fix(discord): immediately defer interactions to prevent timeouts

by Gitjay11 open 2026-02-18 11:53 View on GitHub →
channel: discord size: S
## Summary - Problem: Discord component interactions (buttons, select menus, modals) time out with "This component has expired" because `interaction.defer()` is called AFTER slow DM auth checks and session store lookups, exceeding Discord's 3-second ACK window. - Why it matters: Users see broken "component has expired" errors and interactions fail silently, degrading the Discord experience. - What changed: Moved `interaction.defer()` / `interaction.acknowledge()` to be the very first async operation in all component interaction handlers in [agent-components.ts], before any auth, allowlist, or session store checks. - What did NOT change (scope boundary): No changes to slash command handling (native-command.ts) , exec approval buttons (exec-approvals.ts), message listeners, or any business logic — only the ordering of the ACK call within existing handlers. ## Change Type (select all) - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [ ] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [x] Integrations - [ ] API / contracts - [ ] UI / DX - [ ] CI/CD / infra ## Linked Issue/PR - Closes #19909 ## User-visible / Behavior Changes - Discord component interactions (buttons, select menus, form submissions) no longer show "This component has expired" when the server is under load or auth checks are slow. - No config changes or new defaults. ## Security Impact (required) - New permissions/capabilities? [No] - Secrets/tokens handling changed? [No] - New/changed network calls? [No] - Command/tool execution surface changed? [No] - Data access scope changed? [No] ## Repro + Verification ### Environment - OS: Windows - Runtime/container: Node.js - Model/provider: N/A - Integration/channel (if any): Discord - Relevant config (redacted): Default Discord config with agent components enabled ### Steps 1. Trigger a Discord component interaction (click a button or select menu) when the server has moderate load or DM auth checks are slow (>3s). 2. Observe that the interaction no longer times out with "This component has expired". 3. Run `npx vitest run src/discord/monitor.test.ts` — all 53 tests pass. ### Expected - Interaction is acknowledged within 3 seconds; user sees the expected response. ### Actual - Before fix: "This component has expired" error after ~5.6s (`Slow listener detected: InteractionEventListener took 5642ms`). - After fix: Interaction is deferred immediately; processing continues in the background. ## Evidence Attach at least one: - [x] Failing test/log before + passing after - [x] Trace/log snippets - [ ] Screenshot/recording - [ ] Perf numbers (if relevant) Log before fix: [EventQueue] Slow listener detected: InteractionEventListener took 5642ms for event INTERACTION_CREATE Test results after fix: ✓ src/discord/monitor.test.ts (53 tests) 57ms Test Files 1 passed (1) Tests 53 passed (53) ## Human Verification (required) - Verified scenarios: All 53 existing Discord monitor tests pass after the change. - Edge cases checked: Modal submissions use `acknowledge()` instead of `defer()`; handlers that set `defer: false` (modal triggers) are correctly skipped; error replies use correct `replyOpts` after deferral. - What you did **not** verify: Live Discord bot testing under real network latency (requires deployment). ## Compatibility / Migration - Backward compatible? (Yes) - Config/env changes? [No] - Migration needed? [No] ## Failure Recovery (if this breaks) - How to disable/revert this change quickly: Revert the changes — single file change in [agent-components.ts] - Files/config to restore: [src/discord/monitor/agent-components.ts] - Known bad symptoms reviewers should watch for: Double-reply errors if Discord receives two ACKs, or ephemeral flag mismatch on deferred responses. ## Risks and Mitigations - Risk: If `defer()` itself throws unexpectedly, subsequent `interaction.reply()` calls may fail since the interaction was never acknowledged. - Mitigation: The existing `try/catch` around `defer()` logs the error and falls back to setting `replyOpts.ephemeral = true`, so replies still attempt to go through. <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes Discord interaction timeouts by reordering async operations to ensure `defer()` / `acknowledge()` is called as the first async operation in component interaction handlers, before slow DM auth checks and session store lookups that can exceed Discord's 3-second ACK window. - `handleDiscordComponentEvent`, `AgentComponentButton.run`, `AgentSelectMenu.run`: `resolveInteractionContextWithDmAuth` (which internally calls `defer()`) is moved before component data parsing, ensuring the interaction is deferred within Discord's 3-second window. - `DiscordComponentModal.run`: `interaction.acknowledge()` is moved to the very top of the handler before any validation or auth checks. - `handleDiscordModalTrigger`: `resolveInteractionContextWithDmAuth` is moved earlier for consistency, though this path uses `defer: false` (since modals require `showModal()` as the response), so it does not benefit from the timeout fix. - Error reply paths changed from hardcoded `ephemeral: true` to `...replyOpts` spread, which correctly adapts based on whether the interaction was deferred. <h3>Confidence Score: 4/5</h3> - This PR is safe to merge — it correctly fixes Discord interaction timeouts by reordering existing async operations, with no changes to business logic. - The change is a straightforward reordering of existing function calls to ensure Discord interactions are acknowledged within the 3-second window. The logic and control flow remain the same. All 53 tests pass. Minor concerns are non-blocking: unnecessary DM auth work in the modal trigger path for invalid components, and ephemeral flags on reply calls after acknowledge() in DiscordComponentModal that have no practical effect. - No files require special attention — the changes are confined to operation ordering within `src/discord/monitor/agent-components.ts`. <sub>Last reviewed commit: 6e49be0</sub> <!-- greptile_other_comments_section --> <sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub> <!-- /greptile_comment -->

Most Similar PRs