#7247: fix(telegram): abort stale getUpdates connections after long-poll timeout
channel: telegram
## Problem
After system sleep or network disruptions, Telegram long-poll `getUpdates` requests can hang on stale TCP connections for up to **500 seconds** (the default HTTP timeout). During this time the bot appears completely unresponsive — no messages are received or processed.
Additionally, when these requests finally time out, grammY throws `"timed out"` but `NETWORK_ERROR_SNIPPETS` only contained `"timeout"`, so the error was not recognized as recoverable and the polling monitor exited permanently.
Fixes #4617. Supersedes #6999.
## Solution
### 1. AbortController-based fetch timeout (`fetch.ts`)
- New `wrapFetchWithTimeout()` wraps the fetch implementation with an `AbortController` + `setTimeout`
- **Only applies to `getUpdates` requests** via `isTelegramGetUpdatesRequest()` filter — uploads and other API calls are unaffected
- Properly composes with any existing caller-provided `AbortSignal`
- Preserves the `preconnect` property on wrapped fetch functions
### 2. Long-poll timeout resolution (`monitor.ts`)
- `resolveTelegramLongPollTimeoutMs()` derives the abort timeout from the runner's configured `fetch.timeout` + a 10-second grace period (`TELEGRAM_LONG_POLL_GRACE_MS`)
- Runner options are now computed once before the restart loop and reused across iterations
### 3. Network error snippet fix (`monitor.ts`)
- Added `"timed out"` to `NETWORK_ERROR_SNIPPETS` so the abort error is correctly classified as recoverable and triggers a retry instead of a permanent exit
## Testing
- **"aborts requests after timeoutMs"** — verifies the fetch wrapper aborts getUpdates after the configured timeout using fake timers
- **"skips timeout for non-getUpdates requests"** — verifies non-getUpdates requests pass through without an abort signal
- All 361 existing Telegram tests continue to pass
## Files changed
- `src/telegram/fetch.ts` — `wrapFetchWithTimeout()`, `isTelegramGetUpdatesRequest()`, `resolveFetchUrl()`
- `src/telegram/monitor.ts` — `resolveTelegramLongPollTimeoutMs()`, snippet fix, runner options reuse
- `src/telegram/bot.ts` — `longPollTimeoutMs` option threading
- `src/telegram/fetch.test.ts` — 2 new tests
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds an AbortController-based timeout wrapper around Telegram fetch calls, scoped to long-poll `getUpdates`, and wires the derived timeout (runner fetch timeout + 10s grace) through the Telegram bot creation path. It also expands recoverable network error detection by including the grammY/undici-style message snippet "timed out", and reuses computed runner options across polling restarts.
Overall, this fits cleanly into the existing Telegram provider structure: `monitor.ts` owns runner lifecycle and restart policy, `bot.ts` wires config into grammY’s client, and `fetch.ts` centralizes runtime/network fetch behavior.
<h3>Confidence Score: 4/5</h3>
- This PR looks safe to merge; changes are localized and covered by targeted tests.
- Main behavior change is a scoped abort timeout for `getUpdates` only, plus a small tweak to network error classification. The main remaining risk is overly-broad URL matching for `getUpdates` detection and edge cases with non-standard fetch implementations.
- src/telegram/fetch.ts (URL matching and timeout wrapper robustness)
<!-- 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
#6463: fix(telegram): improve timeout handling and prevent channel exits
by ai-fanatic · 2026-02-01
86.3%
#6447: fix(telegram): auto-restart polling when grammY runner exits silently
by AugmentAdvertise · 2026-02-01
85.7%
#10850: fix(telegram): await runner.stop() to prevent polling race conditio...
by talhaorak · 2026-02-07
82.8%
#7141: fix(telegram): unify network error detection to prevent poll crashes
by hclsys · 2026-02-02
82.4%
#12870: fix: recover from telegram fetch errors (issue #12835)
by ambicuity · 2026-02-09
82.1%
#10509: fix(telegram): bare abort words bypass debounce + clear buffered me...
by romancircus · 2026-02-06
81.0%
#3186: fix(telegram): sanitize update offset + lock polling
by daxiong888 · 2026-01-28
80.8%
#8166: fix(telegram): lifecycle fixes for duplicate messages and auto-reco...
by cheenu1092-oss · 2026-02-03
80.7%
#11688: feat(telegram): add health check watchdog for long-polling
by rmfalco89 · 2026-02-08
79.2%
#5561: fix(telegram): auto-restart on timeout + lower API timeout to 60s
by jesseproudman · 2026-01-31
77.9%