Skip to content

feat: rebuild Telethon's TL classes against the current MTProto layer - #189

Open
artgas1 wants to merge 1 commit into
chigwell:mainfrom
artgas1:feat/telethon-layer-patch
Open

feat: rebuild Telethon's TL classes against the current MTProto layer#189
artgas1 wants to merge 1 commit into
chigwell:mainfrom
artgas1:feat/telethon-layer-patch

Conversation

@artgas1

@artgas1 artgas1 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #188. That PR makes schema drift visible; this one fixes it.

The problem

Telethon releases lag behind production Telegram. As of 2026-08-11 the newest release — 1.44.0, published 2026-06-15 — is built for LAYER 227, while the server answers with LAYER 228 objects, where the user constructor changed (0x317743880xb1b8cc83).

Upgrading is not an option: 1.44.0 is the latest published release, and the v1 branch on GitHub is frozen at LAYER 222 with a "Migrate off GitHub" commit.

The symptom is partial and misleading, because an unknown constructor desynchronises the whole read buffer rather than dropping a single field:

Broken Working
list_chats, get_common_chats, resolve_username, get_full_user get_chats, search_contacts, list_messages, send_message

Which account you use matters too — an account whose dialogs are all bots parsed fine, while a busy personal account failed, because the drift only bites when an affected object actually appears in the response.

The change

scripts/patch_telethon_layer.py regenerates telethon/tl/{types,functions,alltlobjects.py} from a vendored schema using the vendored Telethon generator. The rest of the library — client, networking, tl/custom — is untouched, so this is not a fork of Telethon, only a refresh of its generated classes.

uv run python scripts/patch_telethon_layer.py            # apply
uv run python scripts/patch_telethon_layer.py --check     # compare installed vs vendored layer
uv run python scripts/patch_telethon_layer.py --restore   # roll back from the automatic backup

Idempotent; writes a backup of the original next to the package on first run, so rolling back needs no reinstall.

Verification

  • On a live account: get_entity(<username>) and get_dialogs(limit=5) both failed before the patch and both succeed after it.
  • Cycle: --check--restore → apply → re-run (reports "already LAYER 228 — nothing to do").
  • Full suite green (271 passed).

One implementation note worth flagging: the post-patch check must run in a separate process. In-process, telethon.tl is already imported and Python keeps serving the cached module, so the check reports the old layer and claims failure on a patch that actually succeeded. That bit me while writing it.

Trade-offs — happy to restructure

This is the opinionated part, so please push back:

  1. It vendors ~770 KBvendor/api-layer228.tl (from the Telegram Desktop dev branch) and vendor/telethon_generator/ (from Telethon's v1 branch). I vendored rather than fetched because there is no stable place to fetch the generator from at runtime any more. If you would rather download both on demand, that is a small change.
  2. It mutates an installed dependency. The alternative — publishing a patched Telethon fork to PyPI and pinning it — is cleaner but a much bigger commitment for someone to maintain.
  3. Already running processes keep the old code in memory, so a restart is required after applying. Documented in the README section and in the script.

If you would prefer to take only #188 and leave this out, that is completely reasonable — it is a stopgap by nature. The moment Telethon publishes a release for the current layer, the vendored schema and this script should be deleted.

Telethon releases lag behind production Telegram. As of 2026-08-11 the
newest release (1.44.0) is built for LAYER 227 while the server answers
with LAYER 228 objects, where the `user` constructor changed
(0x31774388 -> 0xb1b8cc83). Upgrading is not an option — 1.44.0 is
already the latest published release.

An unknown constructor desynchronises the whole read buffer, so the
failure is partial and misleading: list_chats, get_common_chats,
resolve_username and get_full_user break while get_chats,
search_contacts, list_messages and send_message keep working. Verified
on a live account: get_entity() and get_dialogs() failed before the
patch and succeed after it.

scripts/patch_telethon_layer.py regenerates
telethon/tl/{types,functions,alltlobjects.py} from the vendored schema
using the vendored Telethon generator, leaving the rest of the library
untouched. It has --check and --restore, is idempotent, and writes a
backup of the original next to the package on first run.

vendor/api-layer228.tl comes from the Telegram Desktop dev branch;
vendor/telethon_generator/ from Telethon's v1 branch, which is frozen on
GitHub at LAYER 222 ("Migrate off GitHub"), so there is nowhere to fetch
it from at runtime.

vendor/ is excluded from black and flake8 — third-party code stays
byte-identical to upstream so it remains diffable on refresh.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant