Skip to content

Messages don't load for new sessions due to race condition #260

Closed

Description

@kmizzi

Summary

When a new session is started from the CLI, message history may not load on the mobile app due to a race condition between session encryption initialization and message fetching.

Severity

High

Affected

Sessions started from CLI that user quickly navigates to on mobile

Root Cause

The fetchMessages function requires session encryption to be initialized (via fetchSessions), but if the user navigates to a session before fetchSessions completes, fetchMessages silently returns early without fetching messages. The InvalidateSync pattern only retries on thrown errors, not silent returns.

Flow That Fails

CLI creates new session
       ↓
Server sends "new-session" WebSocket update
       ↓
Mobile receives update, calls sessionsSync.invalidate()
       ↓
User navigates to the session (e.g., from push notification)
       ↓
onSessionVisible(sessionId) is called
       ↓
fetchMessages() runs BUT encryption isn't ready yet
       ↓
getSessionEncryption(sessionId) returns NULL
       ↓
fetchMessages() returns early (silent, no error thrown)
       ↓
isLoaded stays FALSE, user sees loading spinner forever
       ↓
fetchSessions() eventually completes, sets up encryption
       ↓
But fetchMessages was already "completed" - no automatic retry

Key Code Locations

  • sources/sync/sync.ts:1402-1406 - Early return when encryption not ready
  • sources/sync/sync.ts:188-194 - onSessionVisible creates the fetch sync
  • sources/sync/encryption/encryption.ts:90-92 - getSessionEncryption returns null if not initialized
  • sources/utils/sync.ts - InvalidateSync uses backoff for retries, but only on thrown errors

Reproduction

  1. Start a new Claude Code session from CLI
  2. Quickly open the session on mobile (e.g., via push notification)
  3. Messages may not load, showing loading spinner indefinitely

Potential Fixes

  1. Throw an error instead of returning - Change the early return to throw, triggering backoff retry
  2. Wait for session encryption - Add await sessionsSync.awaitQueue() before fetching messages
  3. Re-invalidate after sessions load - After fetchSessions completes, re-trigger fetchMessages for visited sessions
  4. Queue message fetches - If encryption isn't ready, queue the fetch to run after initialization

Activity

  1. added a commit that references this issue on Dec 3, 2025
    8e2c2c9
  2. kmizzi commented on Dec 3, 2025

    @kmizzi
    ContributorAuthor

    Fix submitted in PR #262: #262

  3. added a commit that references this issue on Dec 6, 2025
    a7a462d
  4. added a commit that references this issue on Dec 6, 2025
    5160c61
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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions