← Back to PRs

#19911: fix(slack): bind `this` context for `app.options()` in slash command arg menus

by myra-tapcart open 2026-02-18 09:07 View on GitHub →
channel: slack size: XS
## Problem Since v2026.2.17, the Slack channel provider crashes immediately on startup with: ``` [default] channel exited: Cannot read properties of undefined (reading 'listeners') ``` The provider enters a 1/10 → 10/10 crash loop and never recovers. Slack is completely non-functional. ## Root Cause `registerSlackMonitorSlashCommands` → `registerArgOptions()` destructures `ctx.app.options` into a local variable: ```typescript const optionsHandler = (ctx.app as unknown as { options?: ... }).options; // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // detached from `this` — classic JS footgun optionsHandler(SLACK_COMMAND_ARG_ACTION_ID, ...); // `this` is `undefined` inside Bolt's App.options() ``` Bolt's [`App.options()`](https://github.com/slackapi/bolt-js/blob/main/src/App.ts#L849) pushes to `this.listeners`, but `this` is `undefined` because the method was called without its receiver. Other Bolt methods in the same file (`ctx.app.action()`, `ctx.app.command()`, `ctx.app.view()`) are called directly on the app instance and work fine. Only `options` was destructured. ## Fix ```diff - ).options; + ).options?.bind(ctx.app); ``` One-line fix. Preserves `this` binding. The optional chain (`?.`) keeps the existing guard for environments where `options` may not exist. ## Stack Trace ``` TypeError: Cannot read properties of undefined (reading 'listeners') at options (App.ts:849:10) at registerArgOptions (subagent-registry-DN6TUJw4.js:48854:3) at registerSlackMonitorSlashCommands (subagent-registry-DN6TUJw4.js:48881:2) at monitorSlackProvider (subagent-registry-DN6TUJw4.js:49075:2) ``` ## Verification Patched the bundled dist on a live 2026.2.17 instance. Before: crash loop. After: `slack socket mode connected` — full inbound/outbound working. ## Affected Versions - **Broken:** v2026.2.17 - **Working:** v2026.2.15 Fixes #19788 Ref: #8404 <!-- greptile_comment --> <h3>Greptile Summary</h3> One-line fix for a critical crash-loop in the Slack channel provider introduced in v2026.2.17. The `App.options()` method from `@slack/bolt` was destructured into a local variable, detaching it from its `this` context. Since Bolt's `App.options()` internally accesses `this.listeners`, calling the detached method throws `Cannot read properties of undefined (reading 'listeners')`, crashing the provider on startup. - Adds `.bind(ctx.app)` when extracting `options` from the Bolt app instance, preserving the method's `this` context - The `?.` optional chain is retained so environments where `options` doesn't exist continue to work via the existing `typeof optionsHandler !== "function"` guard - Other Bolt methods (`ctx.app.command()`, `ctx.app.action()`) are called directly on the instance and were unaffected <h3>Confidence Score: 5/5</h3> - This PR is safe to merge — it is a minimal, well-understood one-line fix for a critical crash-loop regression. - The fix is a single-line change that correctly addresses a classic JS `this`-binding issue. The root cause and solution are clear, the author verified it on a live instance, and the change has no side effects on surrounding code. No new logic or risk is introduced. - No files require special attention. <sub>Last reviewed commit: cf31361</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs