← Back to PRs

#19615: fix(discord): include default account when sub-accounts are configured

by prue-starfield open 2026-02-18 01:13 View on GitHub →
channel: discord size: S
## Summary - **Problem:** When named sub-accounts are added under `channels.discord.accounts`, the implicit default account is silently dropped — the primary Discord bot stops connecting on gateway restart while other bots work fine. - **Why it matters:** Users with multi-bot setups lose their primary bot every time the gateway restarts, with no error or warning. - **What changed:** (1) `createAccountListHelpers` now merges bound account IDs from `bindings` config alongside configured accounts, matching the Telegram implementation. (2) Discord's `listDiscordAccountIds` ensures `DEFAULT_ACCOUNT_ID` is included when a top-level discord token is present. - **What did NOT change (scope boundary):** Token resolution, account config merging, the Telegram implementation (already correct), and all other channel account listing. No config format changes. ## Change Type (select all) - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [x] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [x] Integrations - [ ] API / contracts - [ ] UI / DX - [ ] CI/CD / infra ## Linked Issue/PR N/A — recurring operational issue observed across multiple gateway restarts. ## User-visible / Behavior Changes Discord bots configured via a top-level `channels.discord.token` will no longer disappear when named sub-accounts are also configured under `channels.discord.accounts`. Previously, only the sub-accounts would start; now the default account starts alongside them. ## 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: macOS (Darwin 25.2.0) - Runtime/container: Node 22 - Integration/channel: Discord - Relevant config (redacted): ```json { "channels": { "discord": { "token": "<top-level-default-bot-token>", "accounts": { "bot-b": { "token": "<bot-b-token>" }, "bot-c": { "token": "<bot-c-token>" } } } } } ``` ### Steps 1. Configure a Discord channel with a top-level token AND named sub-accounts under `channels.discord.accounts` 2. Start or restart the gateway 3. Observe gateway logs for `[discord] [default] starting provider` ### Expected All three providers start: `[default]`, `[bot-b]`, `[bot-c]` ### Actual (before fix) Only `[bot-b]` and `[bot-c]` start. `[default]` is missing — the primary bot never connects. ## Evidence - [x] Trace/log snippets **Before fix:** ``` [discord] [bot-b] starting provider (@BotB) [discord] [bot-c] starting provider (@BotC) # [default] is MISSING — no "starting provider" line ``` **After fix:** ``` [discord] [bot-b] starting provider (@BotB) [discord] [bot-c] starting provider (@BotC) [discord] [default] starting provider (@DefaultBot) logged in to discord as <id-1> logged in to discord as <id-2> logged in to discord as <id-3> ``` - [x] Failing test/log before + passing after New test added in `account-helpers.test.ts`: "includes bound account ids from bindings" — verifies that accounts referenced in bindings config are included in the account list. ## Human Verification (required) - **Verified scenarios:** Gateway restart with 3 Discord accounts (1 default + 2 named). All three bots connected and appeared online in Discord after the fix. - **Edge cases checked:** Empty accounts config (returns `["default"]`), accounts with no top-level token (default not injected), accounts that already include `"default"` explicitly (no duplicate). - **What I did NOT verify:** Other channels using `createAccountListHelpers` (Signal, iMessage, Slack, WhatsApp) — the shared helper change adds bound accounts for all channels, but I only tested Discord end-to-end. ## Compatibility / Migration - Backward compatible? `Yes` - Config/env changes? `No` - Migration needed? `No` ## Failure Recovery (if this breaks) - **How to revert:** Revert commit and rebuild. The only behavioral change is that more accounts appear in `listAccountIds` results — reverting returns to the previous (broken) behavior where sub-accounts hide the default. - **Known bad symptoms:** If somehow the default account is injected when it shouldn't be (no top-level token), it would fail to connect with a `tokenSource: "none"` and be filtered out by `listEnabledDiscordAccounts`. No crash risk. ## Risks and Mitigations - **Risk:** The shared `account-helpers` change adds `listBoundAccountIds` for all channels, not just Discord. Channels that previously didn't see bound accounts in their account list now will. - **Mitigation:** This matches the Telegram behavior (which already includes bound accounts) and is the correct semantic — bindings reference accounts that should exist. All existing tests pass (332 tests across discord/routing/account-helpers). AI-assisted (Claude Opus 4.6). Fully tested end-to-end on a live multi-account Discord gateway. <!-- greptile_comment --> <h3>Greptile Summary</h3> Fixes the default Discord account being silently dropped when named sub-accounts are configured under `channels.discord.accounts`. Two targeted changes address this: - **Shared helper (`account-helpers.ts`)**: `listAccountIds` now merges bound account IDs from `bindings` config alongside explicitly configured accounts, matching the pattern already used by the Telegram implementation in `src/telegram/accounts.ts`. - **Discord-specific (`discord/accounts.ts`)**: `listDiscordAccountIds` is promoted from a simple re-export to a wrapper function that injects `DEFAULT_ACCOUNT_ID` when a top-level discord token is present but "default" isn't explicitly listed. Correctly guards against duplicates and uses `resolveDiscordToken` to verify a token actually exists before injecting. **Broader impact**: The shared helper change also adds bound-account awareness to Slack, Signal, WhatsApp, and iMessage (which re-export `listAccountIds` directly). This is consistent with the Telegram precedent and semantically correct—bindings reference accounts that should exist. Accounts without valid tokens/credentials are filtered out downstream by each channel's `listEnabled*Accounts` function. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge — it fixes a clear operational bug with minimal, well-scoped changes that align with existing patterns. - The changes are small, well-tested, and follow the established Telegram pattern. The shared helper change is additive (new accounts may appear in lists but are filtered downstream by each channel's enabled/token checks). No config format changes, no new network calls, no security surface changes. Edge cases (empty accounts, no top-level token, duplicate default) are handled correctly. The new test covers the key behavioral change. - No files require special attention. <sub>Last reviewed commit: 9fbb464</sub> <!-- greptile_other_comments_section --> <sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub> <!-- /greptile_comment -->

Most Similar PRs