Skip to content

Firestore not working offline as expected | setDoc not updating local cache when offline #8696

Description

@vishwa795

Operating System

macOS Sonoma (14.4.1)

Environment (if applicable)

Chrome 131.0.6778.205

Firebase SDK Version

11.0.2

Firebase SDK Product(s)

Firestore

Project Tooling

React app with Webpack

Detailed Problem Description

What I am trying to achieve?

Ability to add documents / update documents while the device is offline.

What actually happened?

Functions like setDoc do not resolve indefinitely until internet is available, which seems like the expected behaviour.

However it's mentioned in docs that when persistance is enabled, firestore will update it's local cache first and trigger a onSnapshot callback (with fromCache and hasPendingWrites true given that includeMetadataChanges is marked true), which doesn't seem to be happening.

Error / Unexpected behaviour

Firestore not updating local cache and not triggering onSnapshot when multi-tab persistance is enabled.

Relevant log snippets or console output

Pasting the debug logs from firestore that I see on browser console, when i go offline, and perform a setDoc operation.

[2025-01-09T07:33:18.212Z]  @firebase/firestore: Firestore (11.0.2): IndexedDbPersistence Starting transaction: updateClientMetadataAndTryBecomePrimary
main.6b4c4e61.js:2 [2025-01-09T07:33:18.213Z]  @firebase/firestore: Firestore (11.0.2): SharedClientState SET firestore_sequence_number_firestore/[DEFAULT]/eka-care-preprod.doctool/ 8736
main.6b4c4e61.js:2 [2025-01-09T07:33:18.213Z]  @firebase/firestore: Firestore (11.0.2): SimpleDb GET owner owner {"ownerId":"zPkMnyOxyJ08NL9MeOHr","allowTabSynchronization":true,"leaseTimestampMs":1736407994210}
main.6b4c4e61.js:2 [2025-01-09T07:33:18.213Z]  @firebase/firestore: Firestore (11.0.2): IndexedDbPersistence Client 'zPkMnyOxyJ08NL9MeOHr' is not zombied in LocalStorage
main.6b4c4e61.js:2 [2025-01-09T07:33:18.213Z]  @firebase/firestore: Firestore (11.0.2): SimpleDb PUT clientMetadata <auto-key> {"clientId":"zPkMnyOxyJ08NL9MeOHr","updateTimeMs":1736407998213,"networkEnabled":true,"inForeground":true}
2main.6b4c4e61.js:2 [2025-01-09T07:33:18.214Z]  @firebase/firestore: Firestore (11.0.2): SimpleDb GET owner owner {"ownerId":"zPkMnyOxyJ08NL9MeOHr","allowTabSynchronization":true,"leaseTimestampMs":1736407994210}
main.6b4c4e61.js:2 [2025-01-09T07:33:18.214Z]  @firebase/firestore: Firestore (11.0.2): IndexedDbPersistence Client 'zPkMnyOxyJ08NL9MeOHr' is not zombied in LocalStorage
main.6b4c4e61.js:2 [2025-01-09T07:33:18.214Z]  @firebase/firestore: Firestore (11.0.2): SimpleDb PUT owner owner {"ownerId":"zPkMnyOxyJ08NL9MeOHr","allowTabSynchronization":true,"leaseTimestampMs":1736407998214}

The above set of logs repeat multiple times in my browser console.

Steps and code to reproduce issue

Firestore Setup

const app = initializeApp(FIREBASE_CONFIG);
const auth = getAuth(app);
setLogLevel('debug');

const FIVE_MB_IN_BYTES = 5000000;

const firestore = initializeFirestore(
    app,
    {
        ignoreUndefinedProperties: true,
        localCache: persistentLocalCache(
            {
                tabManager: persistentMultipleTabManager(),
                cacheSizeBytes: FIVE_MB_IN_BYTES,
            },
        ),
    },
    FIRESTORE_DB_NAME,
);

onSnapshot setup

export default async function setupSnapshotListener({
    queries
    onSnapshot,
    onError,
}: {
    queries: QueryConstraint[];
    onSnapshot?: (snapshot: QuerySnapshot<DocumentData, DocumentData>) => void;
    onError?: (error: FirestoreError) => void;
}): Promise<Unsubscribe> {
    const snapshotQuery = query(collection(firestore, COLLECTION_NAME.TEST), ...queries);

    return onSnapshot(
        snapshotQuery,
        { includeMetadataChanges: true },
        (snapshot) => {
            onSnapshot(snapshot);
        },
        (error) => {
            console.log('Error in apt snapshot', error);
            onError?.(error);
        },
        () => {
            console.log('Snapshot listener completed');
        },
    );
}

Update Document

export async function updateDocument({
    docId,
    data,
}: {
    docId: string;
    data: any;
}): Promise<unknown> {
    const updates = {
        ...data,
        updated_at: Timestamp.fromDate(new Date()),
    };

    await setDoc(doc(documentRef, docId), updates, {
        merge: true,
    }).catch(console.error);

    return updates;
}

In my case, document being updated in updateDocument is always guaranteed to be part of the result set of the query being passed into the onSnapshot.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions