TelegramBotsEvent DeliveryNbility

Telegram Bot Duplicate Replies: Deduplicate Updates Before Calling the Model

Use Telegram update IDs and delivery rules to separate event acceptance, model generation, and sending, including restart and uncertain-send cases.

Telegram Bot Duplicate Replies: Deduplicate Updates Before Calling the Model

One question produces two bot replies. The model may not be the cause: an update can be delivered again, multiple workers can accept it, or a successful send can lose its acknowledgement. Record event acceptance, generation, and sending separately so the fix targets the stage that duplicated work.

This guide was checked on November 10, 2026. The Telegram Bot API page listed Bot API 10.4, November 9, as its latest change. The examples are public teaching records; we did not connect a real bot or reproduce a framework defect.

Use the platform's delivery contract

The Update definition describes update_id as useful for ignoring repeated updates and restoring order. Confirmation differs by delivery method:

  • With getUpdates, an update is confirmed when a later request uses an offset greater than its update_id. Recalculate the offset after each response.
  • With webhooks, Telegram posts updates to the configured endpoint. A response outside 2XY triggers retries. Do not invent a fixed retry schedule that the documentation does not promise.

getUpdates does not work while an outgoing webhook is configured. Inspect the active method before changing it, and do not drop pending updates merely to clear a duplication symptom.

Polling offset and webhook responses confirm delivery through different mechanisms

The documentation also says that after at least a week without new updates, the next identifier is chosen randomly. A permanent highest-seen threshold is therefore not a complete future-event filter. Deduplicating identity and restoring sequence are separate operations.

Accept durably before calling the model

Validate the source and structure using the platform's supported mechanism. Then accept the event under a namespace such as bot identity + update_id, persist a job, and let a worker handle generation.

Acknowledging a webhook before storing anything durable can lose the task on a crash. Waiting for generation and delivery before responding ties slow work to the delivery request. A useful boundary is to acknowledge after reliable acceptance, then recover later processing failures within your own task system.

Validate the source, atomically accept, persist the job, acknowledge, then process

The deduplication record and job creation need a shared reliable transaction boundary. Concurrent delivery of one event should create one job; a duplicate already accepted durably can be acknowledged without another model call. A database unique constraint is one implementation option.

This record is a teaching design, not a native Telegram Update:

{
  "event_key": "demo-bot:1001",
  "state": "accepted",
  "generation_ref": null,
  "send_state": "not_started",
  "sent_message_ref": null
}

An in-memory seen_ids set does not survive restarts or coordinate instances. Interrupted jobs also need a reclaim mechanism. Deleting the acceptance record to recover processing can turn a redelivery into a second full execution.

Input deduplication does not settle an uncertain send

One generation can still produce two send attempts. If Telegram accepts a send but the local caller loses the response, event deduplication cannot tell that caller whether a message exists.

Persist the returned message reference on confirmed success. For an uncertain result, use a distinct pending_confirmation state and inspect available records. Pause for human resolution if there is no reliable way to establish the outcome. Do not assume sendMessage honors an arbitrary business-idempotency header, or regenerate the answer to conceal uncertainty about delivery.

Manage acceptance, saved generation, and send receipts separately; pause uncertain delivery

The side-effect recovery guide covers the same business boundary. Other platforms have different event identities and acknowledgement rules; Telegram's update_id cannot simply be copied into a Feishu or QQ integration.

Verify restart and concurrency behavior

In an isolated bot or local event substitute, check repeated delivery, concurrent acceptance, restart after job persistence, and a lost send acknowledgement. Inspect job count, model-call count, send attempts, and visible messages separately.

We did not run these platform checks, and the research did not establish a current widespread Chinese-community incident. This is a durable-delivery method grounded in the official contract. Use the Hermes Telegram setup guide and connection basics for prerequisites.

Nbility logs can reveal multiple model requests but do not replace bot acceptance or delivery records. Prepare a redacted support record without bot tokens, chat content, or real participant details before investigating the duplicate stage.

Related posts

Run your Agent workflow through Nbility

Get an API key and connect OpenAI-compatible models and developer tools from one place.

Get an API key