Skip to content

chat.list: carry the access hash into the dialog cursor - #17

Merged
erfnzdeh merged 1 commit into
mainfrom
fix/dialog-cursor-access-hash
Sep 10, 2026
Merged

chat.list: carry the access hash into the dialog cursor#17
erfnzdeh merged 1 commit into
mainfrom
fix/dialog-cursor-access-hash

Conversation

@erfnzdeh

Copy link
Copy Markdown
Collaborator

messages.getDialogs resolves its cursor against offset_peer, and both
places that built one used access_hash=0. A hashless peer does not resolve,
so the server answers from the top of the list instead of from the cursor: the
next page repeats the first, and the walk either stops seeing anything new or
returns the same rows forever.

The hash is already in hand. Every getDialogs reply carries the entity for
each peer it mentions, so fetch_dialogs now returns that entity map beside
the rows and both cursor builders use it:

  • _offset_peer resolves the peer through utils.get_input_peer;
  • _peer_state stores the hash in the page cursor, and _state_peer restores
    it, so a resumed page starts where the previous one ended.

Measured on a live 936-dialog account, chat.list at 100 rows per page
following next_cursor: 34 rows in one page before, 600+ across six pages
after.

Both keep the hashless form as a fallback rather than raising: a stalled
cursor loses dialogs, an exception loses the whole call.

Known limits, noted in the code

This is not the whole enumeration story. The fetch_all walk in
_all_dialogs has a separate stall that this does not fix (it still returns
~101 on that same account), and chat.list's has_more is computed after the
type filter is applied, so a filtered page of 34 out of 100 reads as the last
page and drops the cursor. Both are noted where a reader will meet them.

messages.getDialogs resolves its cursor against offset_peer, and both places
that built one used access_hash=0. A hashless peer does not resolve, so the
server answers from the top of the list instead of from the cursor: the next
page repeats the first, and the walk either stops seeing anything new or
returns the same rows forever.

The hash is already in hand. Every getDialogs reply carries the entity for
each peer it mentions, so fetch_dialogs now returns that entity map beside the
rows and both cursor builders use it:

  * _offset_peer resolves the peer through utils.get_input_peer;
  * _peer_state stores the hash in the page cursor, and _state_peer restores
    it, so a resumed page starts where the previous one ended.

Measured on a live 936-dialog account, chat.list at 100 rows per page
following next_cursor: 34 rows in one page before, 600+ across six pages
after.

Both keep the hashless form as a fallback rather than raising: a stalled
cursor loses dialogs, an exception loses the whole call.

This is not the whole enumeration story. The fetch_all walk in _all_dialogs
has a separate stall that this does not fix — it still returns ~101 on that
same account — and chat.list's has_more is computed AFTER the type filter is
applied, so a filtered page of 34 out of 100 reads as the last page and drops
the cursor. Both are noted where a reader will meet them.
@erfnzdeh
erfnzdeh merged commit 2315631 into main Sep 10, 2026
9 of 10 checks passed
@erfnzdeh
erfnzdeh deleted the fix/dialog-cursor-access-hash branch September 10, 2026 17:43
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