Skip to content

[Bug]: Returning to a long thread lands at the top or the middle instead of where I left it #14051

Description

@Vantrongs

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/web

Steps to reproduce

  1. Open a long thread (several hundred messages, many tool calls) and scroll to the bottom.
  2. Switch to another thread.
  3. Switch back.

It also happened right after relaunching the desktop app: the long thread I returned to opened in the middle.

Expected behavior

The transcript returns to where I left it: here, the bottom, on the latest reply.

Actual behavior

It opens at an unpredictable position: sometimes at the very top, sometimes in the middle, with the "Scroll to end" button shown. The result differs between attempts. To continue, I have to scroll all the way down.

Likely cause

From reading the code; the client does not log positions, so I have not confirmed which path fired in my case.

  • MessagesTimeline.tsx saves the thread's position, including atEnd, in handleScroll (lines 1021–1046). It runs on every LegendList onScroll, including scrolls caused by layout, and one frame after every change to rows (lines 1102–1105). Nothing checks that the user scrolled.
  • atEnd is true only within 40 px of the end (resolveTimelineIsAtEnd in MessagesTimeline.logic.ts). If the content is briefly more than 40 px past the viewport while I sit at the bottom, atEnd: false is saved. That can happen when a row is measured taller than its 90 px estimate, or when the composer footer grows: maintainScrollAtEnd deliberately does not re-pin for footer growth.
  • On the next visit, ChatView.tsx (lines 5724–5739) turns live follow off and shows "Scroll to end", and the timeline restores the saved row. If that row is not in the loaded window, it falls back to the saved pixel offset (MessagesTimeline.tsx:873), which lands at the top or in the middle. After a relaunch the thread first loads only the last 10 turns, and a replacement snapshot drops older pages (packages/client-runtime/src/state/threads.ts:453).

The "Scroll to end" button already ignores isAtEnd=false changes that the user did not cause while following (ChatView.tsx:5640–5648). The position save has no such check.

Suggested fix

Save atEnd: false only after user scroll input (the same signal that turns live follow off), or keep atEnd: true while live follow is on.

Impact

Minor bug or occasional failure

Version or commit

0.0.43-nightly.20260924.2200, again on 0.0.43-nightly.20260928.2375; code references are to main @ 94f92a7

Environment

Desktop app on Linux (NixOS, Wayland, niri); provider Claude (Opus 5.5)

Logs or stack traces

Screenshots, recordings, or supporting files

No response

Workaround

Scroll to the bottom by hand.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions