Skip to content

[cloud_firestore]: Snapshot drops field from set() when followed by update() with pending writes #18027

@lukyanov

Description

@lukyanov

Is there an existing issue for this?

  • I have searched the existing issues.

Which plugins are affected?

Cloud Firestore

Which platforms are affected?

iOS

Description

When a document is created with docRef.set() and then docRef.update() is called on the same document before the set() is confirmed by the server, snapshot listeners drop a field from the optimistic state reconstruction.

Expected: all fields from the original set() should be present in the snapshot, merged with any pending update() mutations.

Actual: a plain string field is completely absent from the snapshot data — not even present in map.keys — even though:

  • The field was confirmed present in the data passed to set() (logged immediately before the call)
  • A direct doc.get(GetOptions(source: Source.server)) confirms the server has the field
  • No update() call ever touches or deletes that field
  • Other plain fields from the same set() call are preserved correctly

Diagnostic metadata on the broken snapshot:

  • doc.metadata.hasPendingWrites = true
  • doc.metadata.isFromCache = false

Reproducing the issue

final docRef = FirebaseFirestore.instance.collection('items').doc();

// 1. Create document with set(), do not await
unawaited(docRef.set({
  'ownerId': 'user_123',
  'title': 'Test item',
  'createdAt': FieldValue.serverTimestamp(),
  'status': 0,
}));

// 2. Call update() before the server confirms the set()
await Future.delayed(Duration(milliseconds: 100));
await docRef.update({
  'retryCount': 1,
  'errorMessage': FieldValue.delete(),
});

// 3. A default-source snapshot listener on a query covering this document
//    returns the doc with 'ownerId' missing from the data map.
FirebaseFirestore.instance
    .collection('items')
    .orderBy('createdAt', descending: true)
    .snapshots()
    .listen((snapshot) {
  for (final doc in snapshot.docs) {
    final data = doc.data();
    // 'ownerId' is missing from data.keys entirely
    print('ownerId: ${data['ownerId']}');  // null
    print('title: ${data['title']}');      // 'Test item' ✓
    print('status: ${data['status']}');    // 0 ✓

    // Direct server fetch confirms the field exists
    doc.reference.get(GetOptions(source: Source.server)).then((serverDoc) {
      print('server ownerId: ${serverDoc.data()?['ownerId']}');  // 'user_123' ✓
    });
  }
});

Firebase Core version

4.4.0

Flutter Version

3.38.9

Relevant Log Output

# set() data includes ownerId
[DIAG] ownerId=user_123, data={ownerId: user_123, title: Test item, createdAt: FieldValue(...), status: 0}

# Snapshot listener: ownerId not in keys
[DIAG] ownerId missing, hasPendingWrites=true, isFromCache=false, keys=[title, retryCount, createdAt, status]

# Direct server fetch: ownerId present
[DIAG] server doc: exists=true, ownerId=user_123, keys=[ownerId, title, retryCount, createdAt, status]

Flutter dependencies

Expand Flutter dependencies snippet
Dart SDK 3.10.8
Flutter SDK 3.38.9

- cloud_firestore 6.1.2
- firebase_core 4.4.0
- _flutterfire_internals 1.3.66
- cloud_firestore_platform_interface 7.0.6
- cloud_firestore_web 5.1.2

Additional context and comments

The server data is correct, so the issue is purely in the client-side optimistic state reconstruction. Subsequent snapshots (once all pending writes are confirmed) include the field correctly.

  • Firestore offline persistence is enabled
  • Tested on iOS physical device
  • ListenSource.cache queries correctly show the field — only default-source snapshot listeners are affected

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions