← Back to PRs

#17918: fix(telegram): start webhook listener before setWebhook + forward webhookPort from config

by Glucksberg open 2026-02-16 09:18 View on GitHub →
channel: telegram size: S experienced-contributor
Fixes #12902 ## Problem The Telegram webhook listener calls `setWebhook` (registering the URL with Telegram) **before** the HTTP server is actually listening. This race means Telegram immediately sends a verification request to a port that isn't open yet, resulting in a 502 Bad Gateway. Additionally, the `webhookPort` config field was accepted in the schema but never forwarded to the listener. ## Fix **Reversed startup order** — the HTTP server now binds and starts listening *before* calling `setWebhook`, eliminating the race condition. **Cleanup on failure** — if `setWebhook` fails after the listener is up, the server is properly closed, the bot stopped, and diagnostics halted. Previously a failed `setWebhook` left an orphaned HTTP server. **Resolved port** — uses `server.address().port` for the public URL instead of the configured port, which is critical when port `0` is used (dynamic allocation) and ensures the URL always matches the actual bound port. **webhookPort config forwarding** — the `webhookPort` field from account config is now properly passed through the channel plugin → monitor → webhook pipeline. ## Changes - `src/telegram/webhook.ts` — reversed listen/setWebhook order, added failure cleanup, use resolved port - `src/telegram/monitor.ts` — fall back to `account.config.webhookPort` when no CLI override - `extensions/telegram/src/channel.ts` — forward `webhookPort` from config - `src/config/types.telegram.ts` — add `webhookPort` to type definition - `src/config/zod-schema.providers-core.ts` — add `webhookPort` to zod schema - `src/telegram/webhook.test.ts` — new test for cleanup on setWebhook failure, port resolution assertions - `src/telegram/monitor.test.ts` — updated test to verify webhookPort passthrough - `pnpm-lock.yaml` — removed unused `proper-lockfile` dependency ## Tests All existing and new tests pass: - Verifies server binds before `setWebhook` is called - Verifies resolved port appears in webhook URL (no `:0/` in URL) - Verifies server closes cleanly when `setWebhook` fails - Verifies `webhookPort` config is forwarded from monitor to webhook <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes a race condition in the Telegram webhook startup where `setWebhook` was called before the HTTP server was actually listening, causing Telegram's verification request to hit an unopened port (502). The fix reverses the startup order so the server binds first, then registers the webhook URL with Telegram. Additionally, `webhookPort` from account config is now properly forwarded through the channel plugin and monitor layers. - **Race condition fix**: Server now listens before `setWebhook` is called, ensuring the port is ready for Telegram's verification request - **Port resolution**: Uses `server.address().port` for the public URL, correctly handling dynamic port allocation (port `0`) - **Cleanup on failure**: If `setWebhook` fails after the listener starts, the server is closed, bot stopped, and diagnostics halted — previously this left an orphaned HTTP server - **Config forwarding**: `webhookPort` is now passed from account config through the channel plugin → monitor → webhook pipeline, matching the existing pattern for `webhookHost` and `webhookSecret` <h3>Confidence Score: 5/5</h3> - This PR is safe to merge — it fixes a clear race condition with a well-structured solution and includes appropriate tests. - All changes are focused and correct. The listen-before-register pattern eliminates the race condition. Error cleanup properly tears down the server and bot. The port resolution handles both static and dynamic (port 0) allocation. The webhookPort config forwarding follows existing patterns exactly. Tests cover port resolution and config passthrough. No security concerns, no breaking changes to the public API. - No files require special attention. <sub>Last reviewed commit: ab7c8b2</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs