π Bug Description
The persistUpdate method in src/services/crdtSessionEngine.ts:259-284 has no error handlers for IndexedDB request failures or transaction errors. If the IndexedDB get() or put() operations fail (quota exceeded, corrupted store, race condition from another tab), the failure is silently swallowed and the Yjs update is permanently lost.
Bug location β src/services/crdtSessionEngine.ts:259-284 (approximate):
private async persistUpdate(update: Uint8Array): Promise<void> {
// ...
const db = await openDB();
const tx = db.transaction(YJS_STORE, "readwrite");
const store = tx.objectStore(YJS_STORE);
const getReq = store.get(this.sessionId);
getReq.onsuccess = () => {
// ... store.put(...)
};
// MISSING: getReq.onerror handler
// MISSING: tx.onerror handler
// MISSING: tx.onabort handler
// Outer catch only catches synchronous errors from openDB()
}
The outer try/catch only catches errors from await openDB() β it does NOT catch IDBRequest errors:
} catch (err) {
console.error("[CRDT] Failed to persist update:", err);
}
IndexedDB errors are event-based (not Promise-based), so they do not propagate to the catch block. Without explicit .onerror handlers, these errors are silently discarded.
π Steps To Reproduce
- Start a workout session that uses CRDT-based state sync
- Trigger a condition where IndexedDB operations fail (e.g., storage quota near limit, or rapid concurrent writes from another tab)
store.get() fails β getReq.onerror never fires β function stalls
- OR
store.put() (inside onsuccess) fails β transaction aborts with no handler
- The Yjs update is neither persisted nor retried
- On page reload or session recovery, the persisted snapshot is missing the lost updates
- CRDT state silently diverges
β
Expected Behavior
- Add
getReq.onerror handler to reject the promise
- Add
tx.onerror and tx.onabort handlers for transaction-level failures
- Retry logic for transient IndexedDB failures
β Actual Behavior
- Yjs updates silently lost on IndexedDB errors
- CRDT state diverges from persisted state
- No retry, no fallback, no warning
π Browser
Chrome
π» Operating System
All
π¦ Node.js Version
v20.x
π Additional Context
Impact: Silent data loss in the CRDT sync pipeline. Offline-first session state can diverge from persisted state, causing data loss on page reload.
Note: This is distinct from issue #849 (schema mismatch between CRDT and workoutSyncService) and #837 (state divergence on rapid online-offline toggle).
Level: 2 (Intermediate) β add IndexedDB error handlers
π Bug Description
The
persistUpdatemethod insrc/services/crdtSessionEngine.ts:259-284has no error handlers for IndexedDB request failures or transaction errors. If the IndexedDBget()orput()operations fail (quota exceeded, corrupted store, race condition from another tab), the failure is silently swallowed and the Yjs update is permanently lost.Bug location β
src/services/crdtSessionEngine.ts:259-284(approximate):The outer
try/catchonly catches errors fromawait openDB()β it does NOT catch IDBRequest errors:IndexedDB errors are event-based (not Promise-based), so they do not propagate to the
catchblock. Without explicit.onerrorhandlers, these errors are silently discarded.π Steps To Reproduce
store.get()fails βgetReq.onerrornever fires β function stallsstore.put()(insideonsuccess) fails β transaction aborts with no handlerβ Expected Behavior
getReq.onerrorhandler to reject the promisetx.onerrorandtx.onaborthandlers for transaction-level failuresβ Actual Behavior
π Browser
Chrome
π» Operating System
All
π¦ Node.js Version
v20.x
π Additional Context
Impact: Silent data loss in the CRDT sync pipeline. Offline-first session state can diverge from persisted state, causing data loss on page reload.
Note: This is distinct from issue #849 (schema mismatch between CRDT and workoutSyncService) and #837 (state divergence on rapid online-offline toggle).
Level: 2 (Intermediate) β add IndexedDB error handlers