Why chat IDs change when a Telegram group becomes a supergroup
The bot that stopped working overnight
If you run anything against the Telegram Bot API long enough, you’ll eventually see this: a bot that’s been posting to a group for months suddenly can’t send a single message. No code change, no deploy, no obvious error in your logs except something like “group chat was upgraded to a supergroup chat.” The group is still there. The members are still there. The chat_id your bot has stored is just gone.
This is a Telegram supergroup migration, and it’s not a bug. It’s a deliberate part of how Telegram structures group chats internally, and it catches almost every self-hosted bot and automation setup at some point. Here’s what’s actually happening and how to build around it.
Basic groups and supergroups are different objects
A “basic group” (what you get when you first create a group chat) and a “supergroup” are not the same underlying object on Telegram’s side, even though the app UI makes them look identical. A basic group is a lightweight chat type. A supergroup is implemented as a special kind of channel, the same underlying object type Telegram uses for broadcast channels, just with the megagroup flag set.
That difference matters because channels and basic groups live in separate ID spaces. When Telegram converts a basic group into a supergroup, it isn’t relabeling the existing chat. It’s creating a new channel-type object and retiring the old basic-group object. The membership, message history, and admin list carry over from the user’s point of view, but under the hood you now have a different entity with a different ID.
The Bot API surfaces this distinction with an ID format convention: basic group IDs are plain negative numbers (something like -123456789), while supergroup and channel IDs get a -100 prefix (something like -1001234567890). If you’ve ever wondered why some of your stored chat IDs look longer than others, this is why.
What triggers the conversion
Telegram converts a group to a supergroup in two ways.
The first is automatic. Certain features simply require the channel-based object to exist, so turning them on forces the conversion: enabling admin logs, turning on slow mode, giving the group a public @username, linking it as the discussion group for a channel, or granting more granular admin permissions than a basic group supports. Growing the member list past the ceiling Telegram sets for basic groups also triggers it automatically; Telegram has adjusted that ceiling over time and doesn’t publish a fixed number, so don’t build logic around a specific member count.
The second is manual. Group creators and admins can convert a group on purpose from the group settings (“Upgrade to supergroup” in Telegram Desktop, or the equivalent in mobile clients), usually because they want one of the features above before they’d hit it automatically.
Either way, the timing is not something your bot controls or can predict from your own code. It happens on Telegram’s side, and your bot finds out after the fact.
How the Bot API tells you it happened
When a migration happens, Telegram sends your bot a service update carrying two fields, depending on which side you’re looking at:
migrate_to_chat_idappears on a message in the old chat, telling you the new chat ID the group migrated to.migrate_from_chat_idappears on a message in the new chat, telling you the old chat ID it migrated from.
This is the only reliable signal you get. There’s no separate “migration” webhook event category, no email, no dashboard notice. It’s a field buried in a regular update, and if your update handler isn’t specifically checking for it, you’ll miss it entirely and just start seeing send failures against the old ID with no explanation attached.
Some client libraries surface this as a distinct exception type (for example, a “chat migrated” error raised when you try to send to a chat that’s already moved), which is a second, less graceful way to find out. Relying on that as your only detection method means you find out by breaking, not by being told in advance.
What actually breaks
Anywhere your system treats chat_id as a stable, permanent key, this migration will expose it. In practice that’s usually:
- Hardcoded chat IDs in config files, environment variables, or scheduled job definitions.
- Database rows keyed by chat_id, where a lookup for the old ID now returns nothing.
- Webhook routing logic that maps incoming chat_id to a handler or tenant.
- Logging and analytics pipelines that group events by chat_id, which will suddenly show the group “going silent” while a brand new ID starts appearing with no history behind it.
- Any cron job or external integration that was set up once, pointed at a specific chat_id, and never touched again.
None of this is exotic. It’s just the normal shape of a bot’s configuration, and it’s exactly what a chat_id change quietly breaks.
The userbot and MTProto side
If you’re running accounts through Telethon, Pyrogram, or a raw MTProto client rather than the Bot API, the same underlying migration causes a slightly different failure. Basic groups can be addressed by chat_id alone. Channels, including supergroups, require an access_hash alongside the ID for the server to resolve the peer. That access_hash comes from your client’s local entity cache, populated the last time it saw that chat in a dialog list or update.
When a group migrates, your cached entity for the old chat_id is now stale, and there’s no access_hash for the new channel object until your client refreshes its dialog list or otherwise sees the new chat come through an update. Skip that refresh and you’ll typically hit errors like a failed peer resolution or an invalid channel reference on the next send, not because your session is broken, but because you’re holding a reference to an object that no longer exists.
For anyone running multiple accounts behind proxies for group management or moderation, this is worth building into your session handling directly: treat a migration as a signal to force a fresh dialog sync for that account before touching the chat again, rather than trusting whatever’s already cached.
How to actually handle it
A few concrete habits prevent this from turning into an outage:
Store chat_id as a value you can rewrite, not a constant baked into code. A single row in a small table or config store beats an environment variable you have to redeploy to change.
Handle migrate_to_chat_id and migrate_from_chat_id explicitly in your update handler, and have that handler do exactly one thing: update the stored chat_id for that group and nothing else. Don’t wait for a send failure to notice.
If you missed the live migration event for some reason, don’t try to guess the new ID by reformatting the old one. The -100 prefix pattern is a Bot API display convention, not a documented guarantee you should code against. If the group has a public username, resolve it fresh with getChat instead.
Keep the old ID around as a reference rather than discarding it. A small migrations table linking old chat_id to new chat_id makes historical logs and analytics still make sense after the fact, instead of leaving you with an unexplained gap.
For MTProto-based automations, force a dialog refresh on migration detection rather than reusing a cached peer reference, and don’t assume an old InputPeer object is still valid just because it worked yesterday.
None of this requires much code. It just requires treating the migration as a normal, expected event in a group’s lifecycle rather than an edge case you’ll deal with if it ever comes up.
Wrapping up
A supergroup migration isn’t Telegram breaking your integration. It’s Telegram changing what kind of object your group is, and expecting your bot to notice and adapt, once, quietly, via a field in an update you might not be checking for. Build the handling in from the start and it’s a non-event. Skip it and it’s the kind of failure that looks like your whole bot went down when really one group just grew up.
If you’re running bots, userbots, or account infrastructure that needs to survive this kind of thing without babysitting, that’s the sort of operational detail we build for at telegramvault.org.
Get new guides and videos first — join the Telegram channel.