When a channel or DM has more unread messages than the first page loads, and someone posts while you’re scrolling through that history, every message between the end of the loaded page and the new live message is skipped. The list jumps from the older messages straight to the live one (often hours later), and nothing indicates that anything is missing. Reloading the channel fills the gap back in one page at a time, so a large gap takes several reloads.
This occurs independent of browser or device type (tested on Firefox Desktop and Android and Chrome Android PWA).
Steps to reproduce:
- User A and user B share a DM or channel. User A reads it up to the latest message, then leaves.
- User B posts 60+ messages.
- User A opens the DM. It loads around their last-read message (25 newer messages below).
- Before scrolling to the bottom of that loaded page, user B posts one more message.
- User A scrolls down.
Expected: the next 25-message page loads below, and so on until the live message.
Actual: the live message appears directly after the loaded page. Reaching the bottom requests messages after the live message, the response is empty, can_load_more_future becomes false, and the 35+ messages between are never shown. Because the live message is now visible, last_read_message_id advances past the gap, so the unread indicator clears as well.
Here is my best attempt at figuring out why this is happening:
Since a commit around December 2025 (“FEATURE: respect user presence when chat is on screen”, #36652), ChatChannel#onNewMessage always routes the message through ChatPaneState#handleIncomingMessage, which calls addMessage when auto-scrolling and via maintainScrollPosition otherwise.
ChatMessagesLoader#computeNextTargetMessage uses the last non-staged message in the list as the cursor for a FUTURE page. Once a live message sits at the end of a partially loaded list, that cursor jumps past all the unloaded history.
Then, Chat::MessagesQuery.query_paginated_messages only sets can_load_more_future for FUTURE pages and can_load_more_past for PAST pages. The other is nil. ChatMessagesLoader#loadMore assigns both from result.meta unconditionally, so a single PAST page (scrolling up a little after opening at last-read) sets canLoadMoreFuture to null while history below is still unloaded. Further pagination still works because loadMore checks === false.
On top of that, there is a separate, older bug where #sendNewMessage stages the message at the end of the list without loading the latest page when canLoadMoreFuture is true. Once confirmed, it becomes the FUTURE cursor, so the same skip happens if you reply to older messages in the history you’re reading.
Our community is not primarily chat-focused, but our users do back read frequently, so missing messages in an ongoing conversation you weren’t present for is a problem. I imagine it’ll be a bigger problems for communities that are primary-chat, especially given the new ability to set the homepage as chat.