-
-
Notifications
You must be signed in to change notification settings - Fork 69.2k
Sticky IPv4 fallback resets on polling restart, causing repeated IPv6 timeouts #48177
Description
Problem
When autoSelectFamily=true (Node 22+ default) and the host has unstable IPv6 connectivity to api.telegram.org, the Telegram transport correctly detects the failure and enables a "sticky IPv4-only dispatcher". However, this sticky state is lost on every polling restart, causing a repeating cycle of IPv6 timeouts.
Root Cause
createTelegramBot() in src/telegram/bot.ts:135 calls resolveTelegramTransport() on every invocation, creating a new fetch closure with stickyIpv4FallbackEnabled = false.
When TelegramPollingSession.runUntilAbort() detects a polling stall and restarts, it calls #createPollingBot() → createTelegramBot() → new resolveTelegramTransport() → sticky state reset.
Cycle
1. IPv6 connect timeout (UND_ERR_CONNECT_TIMEOUT)
2. fetch.ts enables stickyIpv4FallbackEnabled = true → works
3. Polling stall detected (~90s no getUpdates)
4. Polling restart → new bot → new transport → sticky reset to false
5. Next fetch tries IPv6 again → timeout
6. Repeat from step 1
Observed Impact
On a host with intermittent IPv6 to Telegram (common with residential ISPs in Asia):
- 47 polling stalls in 20 hours of gateway uptime
- Average ~25 minutes between stalls
- Each stall: 30s-2min of complete message loss (can't receive or send)
sendChatAction,editMessageText,sendMessageall fail during stall- Users perceive bot as "slow" or unresponsive
Log Evidence
[telegram] autoSelectFamily=true (default-node22)
[telegram] dnsResultOrder=ipv4first (default-node22)
[telegram] fetch fallback: enabling sticky IPv4-only dispatcher (codes=UND_ERR_CONNECT_TIMEOUT)
... works for a while ...
[telegram] Polling stall detected (no getUpdates for 99.27s); forcing restart.
[telegram] polling runner stopped (polling stall detected); restarting in 30s.
[telegram] autoSelectFamily=true (default-node22) ← transport recreated, sticky lost
[telegram] dnsResultOrder=ipv4first (default-node22)
[telegram] fetch fallback: enabling sticky IPv4-only dispatcher (codes=UND_ERR_CONNECT_TIMEOUT) ← has to re-discover
Proposed Fix
Hoist resolveTelegramTransport() out of createTelegramBot() so the transport (and its sticky fallback state) is resolved once and reused across polling restarts.
In src/telegram/bot.ts, accept a pre-resolved TelegramTransport in options, falling back to resolveTelegramTransport() only on first creation. The polling session would resolve the transport once and pass it to each bot instance.
Workaround
Users can set channels.telegram.network.autoSelectFamily: false in openclaw.json to permanently disable IPv6 for Telegram. This bypasses the sticky fallback entirely but requires the user to know about the config option.
Environment
- OpenClaw 2026.3.13
- Node 22+
- macOS (Apple Silicon)
- ISP: residential connection with unstable IPv6 routes to Telegram API