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.
[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 blocksgetUpdatespolling entirely, which is its own silent-bot cause (covered below). Ifurlis 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
conflictlines, 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
conflictlines keep arriving with no restart activity to explain them. - Confirm before you hunt: run
ss -tp(orlsof -i) and count the processes holding a connection toapi.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/dnsResultOrderlog lines instead of one. ss -tpshows exactly one process connected toapi.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 handles stale
.jsonl.lockfiles, 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.
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 clickFrequently 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.