You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Optimistic store property readers stay stale after reconciliation removes a property #3883
When an action adds an optimistic row and then retains it in a writable derived store with createFailed: true, a later source update reconciles the row without that property. Both the derived store and its optimistic view then contain { id: "A" }, but JSX reading cards[0]?.createFailed continues displaying Error.
The action has already settled before the source update. There are no pending actions when the stale UI remains.
The failure reproduces without For, routing, or a database.
Direct snapshots after the source update show source, local, and cards all equal to [{ "id": "A" }], while the property-dependent JSX still displays Error.
Published RC.13 renders the reproduction correctly.
A core-only equivalent passes at 41fdf9696 (the merge's parent) and fails at 1b9ceb679 (the merge itself).
It still fails at bc51ada.
The suspected defect is the absent-own-key branch of the store get trap. Present keys go through serveDataKey, which reads through a chained backing unless the outer node carries an optimistic override. The absent-key branch instead returns nodeValue directly, leaving the outer node's cached true visible after the inner store removes the property.
A clarification to the original evidence: JSON snapshots omit the key, but a direct property read can still return the stale true. The core observer also re-runs and reads true, so this is more specific than merely a missed notification.
As an isolated control, inserting this immediately before that absent-key branch makes the core reproduction pass:
Thanks @GabbeV — the bisect to #3774 and your two-line fix were spot on. It landed as-is with tests in #3885 and will ship in rc.14.
Root cause: in an optimistic store over another store, the outer store's per-property node is only a subscription point; the inner store holds the real value unless the outer node carries an optimistic guess. Present keys read through to the inner store, but a key the outer object doesn't have returned the outer node's cached value, so a property reconciliation removed kept showing its last value.
Activity
GabbeV commentedon Oct 7, 2026
Narrowed this to the L2 rewrite in #3774:
41fdf9696(the merge's parent) and fails at1b9ceb679(the merge itself).bc51ada.The suspected defect is the absent-own-key branch of the store
gettrap. Present keys go throughserveDataKey, which reads through a chained backing unless the outer node carries an optimistic override. The absent-key branch instead returnsnodeValuedirectly, leaving the outer node's cachedtruevisible after the inner store removes the property.A clarification to the original evidence: JSON snapshots omit the key, but a direct property read can still return the stale
true. The core observer also re-runs and readstrue, so this is more specific than merely a missed notification.As an isolated control, inserting this immediately before that absent-key branch makes the core reproduction pass:
That is a diagnostic control, not a full-suite-validated patch.
size: raise signals + createStore and compiled hydrating caps for #3883
fix(signals): an optimistic view reads a property its inner store rem…
ryansolid commentedon Oct 8, 2026