firebase / firebase/firebase-js-sdk

hardAssert throws on transient state, permanently poisons Firestore SDK instance (React 19 StrictMode)

Open
#9,729 2 comments 1 reaction 1 assignee Claimed by @MarkDuckworth View on GitHub
api: firestore needs-attention question stack:React
Dominant language
TypeScript
Stars
5.1k
Forks
1k
Avg merge
2d 21h
Merged PRs (30d)
37

Description

### Operating System

macOS

### Environment (if applicable)

React 19, app wrapped in ``. In development, React Strict Mode intentionally re-runs mount/effect logic, which increases the likelihood of overlapping `getDoc()` calls for the same document. React documents these Strict Mode checks as development-only.

### Firebase SDK Version

`firebase 11.10.0` (`@firebase/firestore 4.8.0`) — also reproduces on `11.6.0`

### Firebase SDK Product(s)

Firestore

### Project Tooling

- `firebase 11.10.0` (`@firebase/firestore 4.8.0`) — also reproduces on `11.6.0`
- React 19 with ``
- `initializeFirestore(app, { localCache: memoryLocalCache() })`

### Detailed Problem Description

An internal assertion failure in `@firebase/firestore` appears to leave the Firestore client permanently unusable for the rest of the page session. Once the assertion fires, subsequent Firestore operations fail with cascading internal assertion / AsyncQueue errors until the page is reloaded.

### Expected behavior

A transient internal state inconsistency should not leave the Firestore client permanently unusable for the rest of the page session. If this path is truly unrecoverable, the failure mode should ideally be more contained, or the SDK should expose a supported way to recover / recreate the client cleanly.

### Actual behavior

After the first internal assertion fires, the Firestore client becomes unusable for the remainder of the session. Subsequent operations fail until full page reload.

### Steps and code to reproduce issue

#### Steps

1. Wrap the app in ``.
2. On auth state change, call `getDoc(doc(db, 'users', uid))` inside a `useEffect`.
3. In development, Strict Mode re-runs the effect, making overlapping reads of the same document easier to trigger.
4. In this repro, the overlapping reads appear to create duplicate internal target lifecycle activity.
5. The failure seems to occur in `TargetState.recordTargetResponse()` when `ve` is decremented below zero.
6. `__PRIVATE_hardAssert(this.ve >= 0, 3241, { ve: this.ve })` throws, after which subsequent Firestore operations fail for the remainder of the session.

#### Assertion location

```js
// TargetState.recordTargetResponse()
We() {
this.ve -= 1;
__PRIVATE_hardAssert(this.ve >= 0, 3241, { ve: this.ve });
}

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.