Skip to content

fix(chat): end failed chat loads and restore a chat reopened mid-load - #180

Merged
touch2be merged 1 commit into
akemmanuel:masterfrom
touch2be:fix/chat-load-failures
Oct 25, 2026
Merged

touch2be merged 1 commit into
akemmanuel:masterfrom
touch2be:fix/chat-load-failures

Conversation

@touch2be

Copy link
Copy Markdown
Collaborator

Problem

Opening a chat could leave it blank or loading forever:

  1. No deadline. readSession had none, so a stalled request kept the spinner up indefinitely.
  2. Failure stays "loading". If readSession rejected, hydrateTranscript had no error handling and the transcript stayed in loading. Clicking the same chat again did nothing: activeSessionId didn't change, so no new load started.
  3. A → B → A while B is still loading. When the user returned to A, its stream was still current, so the hydration effect returned early. The transcript store had already switched to B's empty loading scope, so A showed nothing.

Equivalent fixes have been running in production on a patched 0.6.3 Host since 2026-10-16, after users reported exactly these symptoms. This PR ports them onto the current HostProvider.

Change

  • Timeout (host-client.ts): readSession uses AbortSignal.timeout, 15 s by default. It can be configured with sessionReadTimeoutMs.
  • Error state (HostProvider.tsx): a failed hydration dispatches page.failed with sessionError.messagesLoadFailed. This only happens if that chat is still selected.
  • Retry (HostProvider.tsx, MessageList.tsx): selecting the chat already selected while it is in the error state loads it again. A retry first leaves the error scope, so the loading state shows again.
  • Returning mid-load (HostProvider.tsx): returning to the chat whose stream is already loaded re-selects its scope and shows that stream again. B's late response is ignored, as before.
  • UI (MessageListViewportShell.tsx, useMessageListModel.ts): the error view has role="alert" and a "Try again" button (common.retry). The model reads the error from the transcript store.
  • i18n: adds sessionError.messagesLoadFailed in en, de and es.

Tests

All 4 new tests fail on master and pass with this change:

  • HostProvider.render.test.tsx:
    • A → B → A while B is pending keeps A's transcript, including after B resolves.
    • A failed load reaches error, and the retry loads the chat.
  • host-client.test.ts: a stalled snapshot request rejects with a TimeoutError.
  • MessageListViewportShell.test.tsx: the error view offers a retry.

Results:

  • pnpm run check and pnpm run slop-check pass.
  • pnpm run test: 1,623 tests pass.

For review

Returning to A shows the stream as it was loaded. It does not fetch it again, so it behaves like the existing early return. If A changed while it was in the background, the regular event stream still applies.

🤖 Generated with Claude Code

Three ways opening a chat could leave it blank or loading forever:

- A Session snapshot request had no deadline. A stalled request kept the
  spinner up indefinitely. readSession now times out after 15 s.
- A failed snapshot request left the transcript in its loading phase,
  and clicking the same chat again did nothing. The failure now shows the
  translated load error with a retry button; retrying the selected chat
  loads it again.
- Switching A -> B -> A while B was still loading kept B's empty loading
  state on screen, because A's stream was already current and hydration
  was skipped. A's loaded transcript is now shown again, and B's late
  response is ignored.

Adds `sessionError.messagesLoadFailed` in en, de and es.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@touch2be
touch2be merged commit 7933bcc into akemmanuel:master Oct 25, 2026
2 checks passed
@touch2be touch2be mentioned this pull request Oct 25, 2026
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