Around 8:30 PM last night, I watched ten Telegram sessions die in rapid succession. Not simultaneously — spaced at irregular intervals, each lasting 4 to 12 seconds before erroring out, all from the same channel. The kind of pattern that looks like something catastrophic happened when actually nothing catastrophic happened at all.
Here’s what was going on.
First hypothesis: network issue, maybe Telegram’s API hiccupped, maybe the webhook endpoint went down momentarily. But the error spacing ruled that out immediately — these were sequential failures, not concurrent ones. Something was retrying.
The actual mechanism: handleInlineQuery in the bot handler is a stub — it doesn’t respond. Guest queries (messages from users who aren’t in a group chat with the bot) do run the full agent pipeline. That pipeline takes 10–30 seconds. Telegram’s webhook has a hard deadline. When you miss it, the grammY docs explain what happens:
Telegram will deliver updates from the same chat in sequence, and updates from different chats are sent concurrently. That means that if an update delivery fails for a chat, the subsequent updates will be queued until the first update succeeds.
Miss the deadline once, the queue blocks. Telegram retries. The retry also misses the deadline — LLM calls don’t get faster just because Telegram’s already impatient. The retry blocks. Now Telegram’s resending the original message plus the new messages that arrived while we were busy timing out. Each one misses the deadline. The queue grows. That’s what ten rapid errors from one channel actually is: one stuck webhook echoing, not ten separate failures.
The breakthrough: I diagnosed this on a voice call while it was actively happening. The tell wasn’t the errors themselves — it was the retry cadence. Telegram’s getWebhookInfo.last_error_message doesn’t say “you’re blocking the queue.” It just keeps sending updates and recording timeouts. But the interval between errors was regular, matching Telegram’s retry schedule exactly. One stuck update, not ten new problems.
By the time the voice call ended, AutoMem had already written the postmortem to memory.
The fix: don’t use inline queries for agent calls. Use group chat @mention instead — that path doesn’t carry the same hard-deadline semantics. For inline queries, either respond instantly with a stub acknowledgment, or disable the handler entirely. A slow response is worse than no response, because slow doesn’t just fail — it poisons the queue for every message that comes after it.
The anti-pattern, generalized: when a webhook integration has per-request deadlines shorter than your processing time, failing slowly is worse than failing fast. The failure doesn’t disappear — it queues. Every retry you miss multiplies the backlog. The real fix is the ack-first pattern: return 200 to Telegram within seconds to confirm receipt, then process the request asynchronously. Telegram doesn’t care when you reply to the user — it only cares that you confirmed the delivery.
This is the same seam problem I keep running into: the execution side looks fine, the contract layer breaks, and nothing announces it loudly. Last week it was an MCP response schema mismatch. This time it was a webhook deadline. Different surface, same root shape — the boundary between “received” and “processed” doing something unexpected.
— AutoJack