Blog

Telegram 409: "Conflict: terminated by other getUpdates request"

Your gateway log shows Conflict: terminated by other getUpdates request and the bot has gone silent. This is Telegram HTTP 409: Telegram allows exactly one getUpdates long-poll to hold the lease for a bot token at a time, so when two clients poll the same token it terminates one of them. Your OpenClaw channel then enters exponential-backoff auto-restart and drops messages during each window. The most common cause is not misconfiguration — it's two pollers overlapping, usually for a few seconds after rapid back-to-back restarts. Before you touch the token or config, the one rule that matters: do not run getUpdates yourself to test the bot — that call counts as a second poller and causes the exact 409 you're chasing. Use getMe and getWebhookInfo (read-only) instead.

Scope: the 409 rule, the three causes below and the diagnostic advice are Telegram-side and apply to any bot on any framework — aiogram, python-telegram-bot, grammY, node-telegram-bot-api, or a home automation integration. The log paths and the third cause are specific to the OpenClaw runtime, which is what we host.

What you'll see in the log
[telegram] channel exited: Conflict: terminated by other getUpdates request; make sure that only one bot instance is running
auto-restart attempt 3/10 in 8s

The three causes at a glance

One log line, three different root causes. Almost every guide to this error names only the second one. Match the tell before you start hunting for a duplicate bot:

Cause Tell Fix
Transient restart overlap (most common) 409s burst right after a restart, then the log goes quiet Stop restarting and wait. Clean for ~10 minutes means it healed
A real second poller 409s continue with no restart activity, and ss -tp shows two processes on api.telegram.org Find and stop the duplicate: zombie pod, staging copy, local script
Single-instance polling loop 409s at a steady ~30s cadence, but ss -tp shows only one process Not a duplicate — the runtime's probe and poller are colliding. See below

And before any of that: do not call getUpdates yourself to test the bot. That single habit manufactures a fourth 409 that isn't real.

Don't diagnose with getUpdates — it causes the 409

This is the trap that turns a self-healing transient into a reproducible failure. When your bot looks broken, the instinct is to curl Telegram's getUpdates to "see if the token works." Don't. getUpdates opens a long-poll lease, and your running gateway already holds one. The moment your manual call lands, Telegram has two pollers on the token and 409s your gateway's poller offline — so you've just created the failure you were investigating, and the log will keep showing the conflict for as long as you keep poking it.

Use the read-only Telegram Bot API calls, which take no poll lease and are safe to run against a live bot:

  • getMe — confirms the token is valid and returns the bot identity. If this returns your bot, the token is fine; stop chasing "wrong token."
  • getWebhookInfo — confirms whether a webhook is set. A configured webhook blocks getUpdates polling entirely, which is its own silent-bot cause (covered below). If url is empty, no webhook is interfering.

Neither of those will knock your gateway offline. getUpdates will.

Why the bot looks healthy but answers nothing

This failure is deceptive because every health signal is green: the pod is 2/2 Running, the gateway reports ready, and the Telegram provider logs starting provider (@yourbot) plus isolated polling ingress started. And yet the bot consumes nothing. Messages pile up unconsumed in Telegram's queue, because the only component that drains that queue — the getUpdates poller — keeps getting 409'd off the lease and restarted. Each backoff window is a gap during which inbound messages aren't picked up. So "starting provider" plus "ready" plus dead silence is the exact fingerprint of poller contention, not a bad token and not a crashed agent.

A "gateway says ready but the channel is dead" symptom can have other roots too — if the log shows no 409 conflict at all, read why an OpenClaw Telegram/WhatsApp channel stalls at startup instead. The 409 signature here is specific: repeated conflict and auto-restart lines.

Transient restart overlap vs. a real second poller

There are two distinct causes behind one log line. They look identical for the first minute; the fix is different. Tell them apart by watching the log over about 10 minutes (without calling getUpdates).

Transient: restart overlap (self-heals)

By far the more common case. When you restart a Telegram-connected instance, the old gateway's getUpdates long-poll can still be in flight while the new one starts polling — two pollers on one token for a few seconds. This happens most often when two restarts stack: for example a config-change light restart immediately followed by a manual full restart.

  • Tell: the 409s appear in a burst right after a restart, then the log goes clean.
  • Fix: stop restarting and wait. If the log stays clean for about 10 minutes — no new conflict lines, and a test message gets answered — it has healed and there's nothing to fix.
  • Prevent: leave roughly a minute between restarts of a Telegram instance, so the previous poller's long-poll fully releases before the next one starts.

Persistent: a real second poller (won't self-heal)

If the conflicts keep coming long after the last restart, something else is genuinely holding the token's lease. The same bot token is running in two places:

  • A zombie or old pod of the same instance that didn't fully terminate and is still polling.
  • The token reused in a second deployment, a staging copy, or a local script you forgot was running.
  • Tell: new conflict lines keep arriving with no restart activity to explain them.
  • Confirm before you hunt: run ss -tp (or lsof -i) and count the processes holding a connection to api.telegram.org. Two or more means the duplicate is real.
  • Fix: find the second consumer and shut it down so exactly one process polls the token. Then confirm the log goes clean.

If that count comes back as one process and the 409s keep arriving anyway, stop looking for a duplicate — you have the third cause, and it is not a duplicate at all.

Only one instance running and still getting 409

This is the case no other guide covers, and the reason "make sure that only one bot instance is running" — the advice inside Telegram's own error message, and the whole of the answer on every forum thread about it — can send you hunting for something that isn't there. Two connections to Telegram can come from a single process.

OpenClaw issues #50064 and #58951 document the mechanism. resolveTelegramTransport() builds a new undici dispatcher every time it is called, with no caching, and it has two call sites: the probe started by channel.ts startAccount(), and the poller started by monitorTelegramProvider(). Both end up holding live TCP connections to api.telegram.org for the same token, so Telegram sees two sessions and 409s one.

Two details explain why it then never clears on its own:

  • The long-poll timeout is 30 seconds and the maximum retry interval is also 30 seconds, so each retry fires while the previous call's server-side connection is still alive — the retry collides with its own predecessor.
  • The health monitor re-probes on a 300-second interval. Even when a conflict does clear, the next probe re-opens the second connection and starts it again.

The reporter on #58951 confirmed "single gateway instance, single Telegram bot token, zero external processes" and verified with ss -tp that only one process was connected — and the 409s continued regardless.

The fingerprint

  • 409s arrive at a steady ~30-second cadence rather than in a burst that fades.
  • Startup logs show a duplicated transport-init pair — two autoSelectFamily / dnsResultOrder log lines instead of one.
  • ss -tp shows exactly one process connected to api.telegram.org.
  • Restarting produces a clean window of well under a minute, then the conflicts resume.

What you can actually do about it

Both issues were filed in March 2026 — #58951 against OpenClaw 2026.3.28 (commit f9b1079), #50064 against commit 0537f3e5 — and both are closed without a referenced fix commit. So the honest position is: check your own build rather than assume either that it's fixed or that it still bites. Practically:

  • Confirm the fingerprint first so you don't spend the afternoon looking for a second poller that doesn't exist.
  • Upgrade and re-test before anything else — this is transport-layer behaviour inside the runtime, not something you can configure your way out of.
  • Give a restarted instance more than 30 seconds. The graceful-stop budget is 15 seconds, but the old TCP connections need 30 or more to drain, so a fast restart cycle can hand the new poller a conflict it inherited rather than caused.
  • The workarounds in the issue threads — caching the transport, skipping the offset confirmation — are described by their own authors as partial mitigation, not a fix. Treat them accordingly.

Stop babysitting your OpenClaw box

Fix it once — or stop fixing it for good.

Apply the checklist above and keep self-hosting, or skip the maintenance entirely: run your OpenClaw on managed hosting from $6.90/mo, starting with a 7-day free trial. We handle the stale locks, gateway restarts, version upgrades, and uptime — and you can import your existing instance in a couple of minutes. Cancel anytime.

Managed hosting — from $6.90/mo Your own hosted OpenClaw instance with automatic restarts and version upgrades. Starts with a 7-day free trial — import your current setup, keep your channels, cancel anytime.
$199 managed setup — optional Prefer we do it for you? One workspace configured end-to-end: first-run config, one 30-minute onboarding/debug session, and a 7-day follow-up. Limited weekly slots.
  • Managed hosting handles stale .jsonl.lock files, gateway restarts, and version upgrades for you
  • Import your existing OpenClaw setup in minutes — keep your channels and configuration
  • The optional $199 setup is scoped: no custom development, enterprise/SRE support, or unsupported self-hosting repair

If you would rather compare options first, review OpenClaw cloud hosting or see the best OpenClaw hosting options before deciding.

OpenClaw import first screen in OpenClaw Setup dashboard (light theme) OpenClaw import first screen in OpenClaw Setup dashboard (dark theme)
1) Paste import payload
OpenClaw import completed screen in OpenClaw Setup dashboard (light theme) OpenClaw import completed screen in OpenClaw Setup dashboard (dark theme)
2) Review and launch

Confirm and fix it (self-hosted)

Work from the gateway log, never from getUpdates.

1) Tail the gateway's verbose log

The path follows the pattern /tmp/openclaw/openclaw-*.log. Grep for the relevant lines:

grep -E 'conflict|getUpdates|auto-restart' /tmp/openclaw/openclaw-*.log

2) Read the timeline

If the only 409s line up with your own getUpdates calls and the log is clean afterward, there is no real second poller — it was self-inflicted or a transient restart overlap. Stop poking it.

3) Rule out a webhook

Run getWebhookInfo (safe). A non-empty url means a webhook is set, which blocks getUpdates polling — delete the webhook if you intend to poll.

4) For the persistent case, kill the duplicate

Track down the zombie/old pod or the second process/host using the token and stop it. Ensure exactly one consumer of the token.

5) Confirm it's fixed by message flow, not by health checks

Tail the gateway log and send one message. You should see an inbound line like Inbound message ... -> @yourbot followed by outbound send ok. That round trip — not "ready" — is proof the channel is alive.

A note on the token: a placeholder in config is normal

If you're on managed hosting and you inspect the config, don't be alarmed by what you find. On a managed instance the botToken value in openclaw.json is the literal placeholder ${TELEGRAM_BOT_TOKEN}, and there may be no Telegram token visible in the process environment. This is expected, not a bug. The real token is resolved at runtime from a dotenv file the init container writes. Seeing a placeholder in the config or no token in /proc/<pid>/environ is normal — it is not evidence that your token is wrong, so don't go re-issuing tokens over it. (getMe returning your bot already settled the "is the token valid" question.)

How managed hosting avoids the double-poll window

The transient 409 is fundamentally a restart-sequencing problem: two restarts overlap and you get two pollers. On managed OpenClaw hosting from Lobsterland, restarts are tiered so they don't stack. Token or credential changes do a single full pod rollout — the init container regenerates the runtime env, then the gateway comes up once. Config-only edits (allowlist, allow-anyone, disconnect) on recent versions do a single light in-place gateway restart — a SIGTERM to PID 1, back to ready in roughly 35 seconds — instead of a second full restart on top of the first. The point isn't speed; it's that there's one controlled restart path per change, so two pollers don't get launched against the same token in the same moment. You bring your own model keys; there are no servers to run and no restart sequence to hand-time.

What hosting does not do: the single-instance polling loop above lives in the runtime's own Telegram transport, and we don't patch it. Managed hosting sequences restarts and runs pinned, tested builds — it does not remove an upstream transport bug, and no host can honestly claim otherwise.

Import your current OpenClaw instance in 1 click

Frequently asked questions

What does "Conflict: terminated by other getUpdates request" mean in OpenClaw Telegram?

It's Telegram HTTP 409. Telegram permits only one getUpdates long-poll per bot token at a time. The message means two clients are polling the same token simultaneously, so Telegram terminated one. In OpenClaw it surfaces as [telegram] channel exited: Conflict: terminated by other getUpdates request, followed by auto-restart attempts.

Why is my OpenClaw Telegram bot showing healthy/ready but not responding to messages?

Because health and message consumption are separate. The pod can be 2/2 Running, the gateway ready, and the provider logging starting provider (@yourbot) while the getUpdates poller keeps getting 409'd off the token's lease and restarted. Nothing drains Telegram's queue during those backoff windows, so messages pile up and the bot looks alive but answers nothing.

Does calling getUpdates to test my bot cause the 409 conflict?

Yes. getUpdates opens a long-poll lease, and your gateway already holds one. Your manual call becomes the second poller and 409s the gateway's poller offline — you create the exact failure you're diagnosing. Use the read-only getMe and getWebhookInfo calls instead; they take no lease.

Is the Telegram 409 getUpdates conflict permanent or does it fix itself?

It depends which of the three causes you have. A transient overlap from rapid back-to-back restarts self-heals once the old poller's long-poll releases — clean for about 10 minutes means it's fixed. A second poller running the same token elsewhere will not self-heal until you shut it down. A single-instance polling loop, where the runtime's own probe and polling connections collide, does not self-heal either: the 30-second long-poll matches the 30-second retry interval, so each retry lands on top of the previous one.

How do I find the second poller / duplicate instance using my bot token?

Tail the gateway log (/tmp/openclaw/openclaw-*.log, grep conflict|getUpdates|auto-restart) and check whether conflicts keep arriving with no restart activity to explain them. Then confirm a second consumer actually exists before hunting one: run ss -tp and count the processes holding a connection to api.telegram.org. If there really are two, look for a zombie or old pod of the same instance, or the token reused in a second deployment, staging copy, or local script. If only one process is connected and the 409s continue, you have the single-instance polling loop instead, not a duplicate.

I only have one bot instance running and still get 409 Conflict — why?

Because two connections to Telegram can come from one process. OpenClaw issues #50064 and #58951 describe a self-sustaining loop in which resolveTelegramTransport() builds a new, uncached undici dispatcher at each of its two call sites — the probe started by channel.ts startAccount() and the poller started by monitorTelegramProvider() — so both hold live TCP connections to api.telegram.org against the same token. The fingerprint is 409s arriving at a steady ~30-second cadence with no restart activity, a duplicated transport-init log pair at startup, and ss -tp showing only one process. Both issues were reported in March 2026 (OpenClaw 2026.3.28 / commit 0537f3e5) and are closed without a referenced fix commit, so check your own build before assuming it applies.

Does a Telegram webhook block getUpdates polling, and how do I check with getWebhookInfo?

Yes — a configured webhook and getUpdates polling are mutually exclusive; a set webhook blocks polling. Check it with getWebhookInfo (read-only, safe to run against a live bot). If the returned url is non-empty, a webhook is set; delete it if you intend to poll.

How long should I wait between restarting a Telegram-connected OpenClaw instance?

Leave roughly a minute between restarts. That gives the previous gateway's getUpdates long-poll time to release the lease before the next one starts polling, which avoids the overlap that produces the transient 409.

Cookie preferences