Skip to content

PWA hangs on infinite "Loading…" when a stale older-version same-origin tab holds the OPFS DB #283

Description

@Stvad

Summary

When the app is open in two places on the same origin — e.g. the installed Android PWA plus a browser tab still running an older deployed version — the newer instance can hang indefinitely on the "Loading…" screen. Closing the stale tab unblocks it immediately.

Observed (real Android device)

  • Installed PWA (Chrome-backed) on stvad.github.io/knowledge-medium.
  • A separate same-origin Chrome tab was open, running an older bundle — it was showing the "A new version is available. Reload" prompt.
  • The PWA sat on "Loading…" indefinitely. Via remote inspection: document.readyState === "complete" and no JS exception was thrown — boot was blocked, not the HTML/network load.
  • Closing the stale tab → the PWA booted immediately.

Likely mechanism

  • DB layer: PowerSyncDatabase with WASQLiteVFS.OPFSCoopSyncVFS and flags.enableMultiTabs: true (src/data/repoProvider.ts).
  • The cooperative OPFS VFS coordinates tabs via a shared worker / navigator.locks, which assumes open tabs run compatible code. With the older-version tab holding the cooperative handle, the newer instance appears to starve at DB-open.
  • Not fully confirmed — would be nailed by reproducing two matched-version tabs (expected: coexist fine) vs mismatched (expected: wedge). On Android the installed PWA shares an OPFS partition with same-origin browser tabs, so this is easy to hit: open the app in a tab, don't reload after a deploy, then launch the PWA.

Impact

Indefinite "Loading…" with no feedback — the user can't tell why the app won't start, and the natural instinct (reload the PWA) doesn't help; only closing the other tab does. Baffling failure mode on the user's primary device.

Proposed fix

  • DB-open / boot timeout → actionable message. If the connection doesn't open within N seconds, replace the infinite spinner with something like "The app appears to be open in another tab, possibly running an older version — close or reload it," rather than hanging silently.
  • Tie into the existing version/update flow (the "new version available" prompt) so a version-skewed tab is nudged to reload before it can wedge a sibling.
  • Optional: detect the coordination stall explicitly and name which tab holds the lock.

Notes

Discovered while debugging the mobile keyboard toolbar on a real Android device via remote CDP inspection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — improvement with a mild trigger presentbugSomething isn't workingdata-layerRepo, sync, PowerSync, schema, storage

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions