[REQUIRED] Describe your environment
- Firebase JS SDK version: pinned by FlutterFire to 12.14.0 (current), but the same crash is reproducing across releases spanning JS SDK 12.2.1 → 12.14.0 in our production telemetry (i.e. it survives multiple SDK bumps, not tied to one version)
- Firebase Product: Auth (
indexedDBLocalPersistence)
- Integration path: FlutterFire
firebase_auth: 6.5.2 / firebase_auth_web: 6.2.2 / firebase_core_web: 3.8.0 (Flutter Web)
- Browsers affected (from our error tracker, last ~3 months, production): Mobile Safari, Safari, Chrome (desktop), Chrome Mobile, Chrome Mobile iOS, Edge, and in-app browsers (Instagram webview) — cross-browser, not Safari-specific
- Platforms: patient- and clinician-facing Flutter Web apps
Split out from #2710
Per @hsubox76's request in #2710: that thread is scoped to Firestore, while this and the last couple of reports there are all Auth, on Flutter Web. Filing this separately so it reaches the right owners.
[REQUIRED] Describe the problem
Steps to reproduce
Not reliably reproducible on demand yet (see note below on the non-Flutter repro ask) — but consistently reproduces in production under normal usage: page load / tab foregrounding after the browser has been backgrounded or the IndexedDB connection has been torn down (tab close, reload, storage eviction, OS memory pressure evicting the tab). It is not tied to a specific user action — it fires from the SDK's own background persistence poller, so there's no application code path that triggers it and no way for consumers to catch it.
Relevant Code / stack trace
Captured stack (from our original report in #2710):
InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.
at isReadWrite (auth/src/platform_browser/persistence/indexed_db.ts:79)
at _poll → getObjectStore(db, false).getAll() (indexed_db.ts:363)
at _withRetries (indexed_db.ts:208)
Sequence: the background _poll() runs → _withRetries catches an underlying IndexedDB error and calls db.close() → the retry then calls .transaction() on the now-closing connection → InvalidStateError (DOMException.code 11), surfacing as an unhandled promise rejection. We also see a sibling UnknownError: An internal error was encountered in the Indexed Database server immediately before it in the same session.
@flt-phy reported the same file/line signature independently after bumping to JS SDK 12.5.0, also via Flutter Web + firebase_auth.
Production telemetry (Sentry), last ~3 months
Two of our top clusters (there are several smaller ones with the identical signature):
| Issue |
Events |
Users |
Where it fires |
App releases seen on |
| Cluster A |
323 |
306 |
app root / /patient |
3.16.0+150, 3.20.1+159, 3.18.0+154 |
| Cluster B |
136 |
127 |
app root / /patient/login |
3.20.0+156, 3.20.1+159, 3.18.0+154 |
Combined with the smaller clusters carrying the same message, we're at roughly 500+ events / 450+ distinct users in this window, spread across unrelated app deploys — i.e. it's not caused by one of our releases, it's continuous background SDK behavior. Browser breakdown for Cluster A: Mobile Safari 98, Chrome 86, Chrome Mobile iOS 38, Edge 17, Safari 17, Instagram in-app 15 (remainder split across others) — confirming this isn't a Safari-only quirk.
None of this is user-visible (no data loss observed on our end, unlike some earlier reports in #2710) — but it's pure noise in our error tracker at meaningful volume, with no application-level way to suppress it since it doesn't originate from a call we make.
On the non-Flutter repro ask
Understood, and agreed that's the most useful thing to nail down — it would rule out FlutterFire's JS interop/teardown handling as the culprit rather than the JS SDK's own persistence poller. We'll attempt a minimal vanilla-JS repro (getAuth() + indexedDBLocalPersistence + tab backgrounding/reload/storage-eviction) and report back here with either a working repro or a clear "doesn't reproduce outside Flutter" result.
Possible direction (for consideration, not prescriptive)
Per @schmidt-sebastian's earlier comment in #2710: user-initiated Auth operations already reject cleanly on IndexedDB failure so calling code can retry. This looks like the one code path that doesn't go through that handling — the background _poll()/_withRetries loop's own retry-after-close() race. If confirmed as SDK-internal (not FlutterFire), catching/discarding InvalidStateError/closing-connection failures specifically inside the poller (rather than the calling code, which is exactly what we don't have a code path to catch) seems like it would fix this at the source without changing user-facing retry semantics.
/cc @flt-phy
[REQUIRED] Describe your environment
indexedDBLocalPersistence)firebase_auth: 6.5.2/firebase_auth_web: 6.2.2/firebase_core_web: 3.8.0(Flutter Web)Split out from #2710
Per @hsubox76's request in #2710: that thread is scoped to Firestore, while this and the last couple of reports there are all Auth, on Flutter Web. Filing this separately so it reaches the right owners.
[REQUIRED] Describe the problem
Steps to reproduce
Not reliably reproducible on demand yet (see note below on the non-Flutter repro ask) — but consistently reproduces in production under normal usage: page load / tab foregrounding after the browser has been backgrounded or the IndexedDB connection has been torn down (tab close, reload, storage eviction, OS memory pressure evicting the tab). It is not tied to a specific user action — it fires from the SDK's own background persistence poller, so there's no application code path that triggers it and no way for consumers to catch it.
Relevant Code / stack trace
Captured stack (from our original report in #2710):
Sequence: the background
_poll()runs →_withRetriescatches an underlying IndexedDB error and callsdb.close()→ the retry then calls.transaction()on the now-closing connection →InvalidStateError(DOMException.code 11), surfacing as an unhandled promise rejection. We also see a siblingUnknownError: An internal error was encountered in the Indexed Database serverimmediately before it in the same session.@flt-phyreported the same file/line signature independently after bumping to JS SDK 12.5.0, also via Flutter Web +firebase_auth.Production telemetry (Sentry), last ~3 months
Two of our top clusters (there are several smaller ones with the identical signature):
/patient3.16.0+150,3.20.1+159,3.18.0+154/patient/login3.20.0+156,3.20.1+159,3.18.0+154Combined with the smaller clusters carrying the same message, we're at roughly 500+ events / 450+ distinct users in this window, spread across unrelated app deploys — i.e. it's not caused by one of our releases, it's continuous background SDK behavior. Browser breakdown for Cluster A: Mobile Safari 98, Chrome 86, Chrome Mobile iOS 38, Edge 17, Safari 17, Instagram in-app 15 (remainder split across others) — confirming this isn't a Safari-only quirk.
None of this is user-visible (no data loss observed on our end, unlike some earlier reports in #2710) — but it's pure noise in our error tracker at meaningful volume, with no application-level way to suppress it since it doesn't originate from a call we make.
On the non-Flutter repro ask
Understood, and agreed that's the most useful thing to nail down — it would rule out FlutterFire's JS interop/teardown handling as the culprit rather than the JS SDK's own persistence poller. We'll attempt a minimal vanilla-JS repro (
getAuth()+indexedDBLocalPersistence+ tab backgrounding/reload/storage-eviction) and report back here with either a working repro or a clear "doesn't reproduce outside Flutter" result.Possible direction (for consideration, not prescriptive)
Per @schmidt-sebastian's earlier comment in #2710: user-initiated Auth operations already reject cleanly on IndexedDB failure so calling code can retry. This looks like the one code path that doesn't go through that handling — the background
_poll()/_withRetriesloop's own retry-after-close()race. If confirmed as SDK-internal (not FlutterFire), catching/discardingInvalidStateError/closing-connection failures specifically inside the poller (rather than the calling code, which is exactly what we don't have a code path to catch) seems like it would fix this at the source without changing user-facing retry semantics./cc @flt-phy