Describe the bug
Synced data from the source collection does not appear in a derived (live query) collection while there is a pending optimistic mutation on that derived collection.
When using createOptimisticAction to insert into a createLiveQueryCollection, any new items that sync into the source collection while the mutation is pending are invisible in the derived collection. The items are processed (the pipeline runs), but they don't appear in the collection's output.
This affects all derived collections, regardless of query complexity (simple passthrough, orderBy, fn.select, multi-stage pipelines).
To Reproduce
- Create a source collection with sync
- Create a derived collection via
createLiveQueryCollection that queries the source - Use
createOptimisticAction to insert an item into the derived collection - While the mutation is pending (mutationFn hasn't resolved), sync a NEW item into the source collection
- Observe that the synced item is invisible in the derived collection
Minimal Reproduction Code
import{createCollection,createLiveQueryCollection,createOptimisticAction,}from'@tanstack/db'interfaceItem{id: stringvalue: string}// 1. Create source collection with controllable syncletbegin,write,commit,markReadyconstsource=createCollection<Item>({id: 'source',getKey: (item)=>item.id,startSync: true,sync: {sync: (params)=>{begin=params.beginwrite=params.writecommit=params.commitmarkReady=params.markReady},},})// 2. Create derived collection (simple passthrough)constderived=createLiveQueryCollection<Item>({query: (q)=>q.from({item: source}),getKey: (item)=>item.id,startSync: true,})// Mark source readymarkReady()// 3. Create optimistic actionletresolveOptimistic: ()=>voidconstoptimisticInsert=createOptimisticAction<Item>({onMutate: (item)=>{derived.insert(item)},mutationFn: async()=>{// Keep mutation pending until we explicitly resolveawaitnewPromise<void>((resolve)=>{resolveOptimistic=resolve})},})// 4. Insert optimistic item (mutation will be PENDING)optimisticInsert({id: 'optimistic-1',value: 'optimistic'})console.log('After optimistic insert:')console.log(' derived.size:',derived.size)// 1 ✓console.log(' has optimistic-1:',derived.has('optimistic-1'))// true ✓// 5. Sync a NEW item into source (while optimistic mutation is pending)begin()write({type: 'insert',value: {id: 'synced-1',value: 'synced'}})commit()console.log('After sync (mutation still pending):')console.log(' derived.size:',derived.size)// Expected: 2, Actual: 1 ✗console.log(' has optimistic-1:',derived.has('optimistic-1'))// trueconsole.log(' has synced-1:',derived.has('synced-1'))// Expected: true, Actual: false ✗// BUG: synced-1 is INVISIBLE while optimistic mutation is pending!// 6. Resolve the optimistic mutationresolveOptimistic()console.log('After mutation resolved:')console.log(' derived.size:',derived.size)// 1 (optimistic dropped, synced appears)console.log(' has synced-1:',derived.has('synced-1'))// true (finally visible)Test Output
After optimistic insert:
derived.size: 1
has optimistic-1: true
After sync (mutation still pending):
derived.size: 1 ← BUG: should be 2
has optimistic-1: true
has synced-1: false ← BUG: should be true
After mutation resolved:
derived.size: 1
has synced-1: true
Expected behavior
When new items sync into the source collection, they should appear in the derived collection immediately, regardless of whether there are pending optimistic mutations.
Expected output:
After sync (mutation still pending):
derived.size: 2 ← Both items visible
has optimistic-1: true
has synced-1: true ← Synced item should be visible
Additional Testing
The bug occurs in all derived collection configurations:
| Configuration | Bug Present |
|---|
Simple passthrough (q.from({ item: source })) | Yes |
With orderBy | Yes |
With fn.select | Yes |
| Multi-stage pipeline (derived → derived) | Yes |
| Streaming (items arrive one at a time) | Yes |
Impact
This bug causes data loss in applications that use optimistic updates with live query collections. In our case, it causes chat messages to intermittently disappear:
- User sends message → optimistic insert (mutation pending, waiting for server sync)
- Server syncs user message back
- Assistant starts responding → synced into source collection
- BUG: Assistant message is invisible because user's optimistic mutation is still pending
- User sees only their message, assistant response is missing
The bug is intermittent because it only manifests when synced data arrives before the optimistic mutation resolves.
Environment
- OS: macOS (Darwin 24.6.0)
- Node: v22.x
- @tanstack/db: (linked local version from TanStack/db repo)
- Browser: N/A (Node.js tests)
Describe the bug
Synced data from the source collection does not appear in a derived (live query) collection while there is a pending optimistic mutation on that derived collection.
When using
createOptimisticActionto insert into acreateLiveQueryCollection, any new items that sync into the source collection while the mutation is pending are invisible in the derived collection. The items are processed (the pipeline runs), but they don't appear in the collection's output.This affects all derived collections, regardless of query complexity (simple passthrough, orderBy, fn.select, multi-stage pipelines).
To Reproduce
createLiveQueryCollectionthat queries the sourcecreateOptimisticActionto insert an item into the derived collectionMinimal Reproduction Code
Test Output
Expected behavior
When new items sync into the source collection, they should appear in the derived collection immediately, regardless of whether there are pending optimistic mutations.
Expected output:
Additional Testing
The bug occurs in all derived collection configurations:
q.from({ item: source }))orderByfn.selectImpact
This bug causes data loss in applications that use optimistic updates with live query collections. In our case, it causes chat messages to intermittently disappear:
The bug is intermittent because it only manifests when synced data arrives before the optimistic mutation resolves.
Environment