Describe the bug
reconcile() never notifies nodes for symbol-keyed store properties:
- An effect (or rendered binding) tracking
state[SYM] never re-runs when reconcile() changes that property.
- Because the stale node then exists, even plain untracked reads of
state[SYM] keep returning the old value — the new value written by reconcile is unreachable. (Without any prior tracked read there is no node, and reads fall through to the swapped value — which is why the bug hides in non-rendering tests.)
This is a remaining variant of #2769. The committed fix (bc92d00) covered symbol keys in the set trap (array metadata writes), storeSetter, storePath, and merge/omit enumeration — all via the new ownEnumerableKeys helper. reconcile()'s diff loops still enumerate with Object.keys, which drops symbol keys, so they were not reached by that fix. String-keyed properties update fine through the identical code path (verified as a control).
Your Example Website or App
https://stackblitz.com/edit/solidjs-templates-krnhumcg?file=src%2FApp.tsx
import { createStore, reconcile } from "solid-js";
const META = Symbol("meta");
export default function App() {
const [store, setStore] = createStore<any>({ id: 1, label: "old", [META]: "old" });
return (
<main style={{ "font-family": "system-ui", padding: "16px" }}>
<h2>reconcile() skips symbol-keyed bindings</h2>
<p>
string key <code>label</code>: <b>{store.label}</b> (control)
</p>
<p>
symbol key <code>[META]</code>: <b>{store[META]}</b>
</p>
<button onClick={() => setStore(reconcile({ id: 1, label: "new", [META]: "new" }, "id"))}>
reconcile fresh data
</button>
</main>
);
}
Steps to Reproduce the Bug or Issue
- Initial render shows both rows at
old.
- Click reconcile fresh data — one
reconcile() carrying the new value for both keys. Actual — the string row updates, the symbol row does not:
string key label: new (control)
symbol key [META]: old
The symbol binding never re-ran, and even a plain store[META] read still returns "old" — the value reconcile wrote is unreachable behind the stale node. The string row, updated by the same call, is the built-in control: the only difference is the key type.
Expected behavior
Symbol-keyed properties reconcile like string-keyed ones — both rows update:
string key label: new (control)
symbol key [META]: new
Screenshots or Videos
No response
Platform
- OS: macOS
- Browser: Chrome
- Version: 2.0.0-beta.15 (re-verified at
next @ e2ebc11c)
Additional context
Root cause: every key enumeration in reconcile's object diff drops symbols (packages/solid-signals/src/store/reconcile.ts):
// reconcile.ts:28-32 — used when the store's $TRACK node is tracked
function getAllKeys(value, override, next) {
const keys = getKeys(value, override) as string[]; // getKeys → Object.keys
const nextKeys = Object.keys(next);
return Array.from(new Set([...keys, ...nextKeys]));
}
// reconcile.ts:187 (applyStateFast) / :337 (applyStateSlow) — untracked path
const keys = tracked ? getAllKeys(previous, undefined, next) : Object.keys(nodes);
Symbol-keyed nodes in the nodes record are invisible to Object.keys(nodes), and symbol keys of next are invisible to getAllKeys, so setSignal is never called for them; the STORE_HAS loops (reconcile.ts:209/:359) have the same gap. Meanwhile applyState* has already swapped STORE_VALUE to next, so the stale node shadows the new value for direct reads too.
Does this exist in Solid 1.x?
Exists in 1.x too — in a worse form. Verified against solid-js 1.9.14: 1.x reconcile doesn't even merge symbol-keyed values (state[sym] stays at the old value after setState(reconcile({ [sym]: 2, a: 2 })); string keys update fine), so no notification question even arises. 2.0 half-fixed this — the value now merges — but subscribers of the symbol-keyed node are still never notified. Not a regression, but 2.0 already handles symbols in its other store paths (getAllKeys, set trap after #2769), so finishing the job in reconcile's diff loops is consistent.
Describe the bug
reconcile()never notifies nodes for symbol-keyed store properties:state[SYM]never re-runs whenreconcile()changes that property.state[SYM]keep returning the old value — the new value written byreconcileis unreachable. (Without any prior tracked read there is no node, and reads fall through to the swapped value — which is why the bug hides in non-rendering tests.)This is a remaining variant of #2769. The committed fix (bc92d00) covered symbol keys in the set trap (array metadata writes),
storeSetter,storePath, andmerge/omitenumeration — all via the newownEnumerableKeyshelper.reconcile()'s diff loops still enumerate withObject.keys, which drops symbol keys, so they were not reached by that fix. String-keyed properties update fine through the identical code path (verified as a control).Your Example Website or App
https://stackblitz.com/edit/solidjs-templates-krnhumcg?file=src%2FApp.tsx
Steps to Reproduce the Bug or Issue
old.reconcile()carrying the new value for both keys. Actual — the string row updates, the symbol row does not:The symbol binding never re-ran, and even a plain
store[META]read still returns"old"— the valuereconcilewrote is unreachable behind the stale node. The string row, updated by the same call, is the built-in control: the only difference is the key type.Expected behavior
Symbol-keyed properties reconcile like string-keyed ones — both rows update:
Screenshots or Videos
No response
Platform
next@e2ebc11c)Additional context
Root cause: every key enumeration in
reconcile's object diff drops symbols (packages/solid-signals/src/store/reconcile.ts):Symbol-keyed nodes in the
nodesrecord are invisible toObject.keys(nodes), and symbol keys ofnextare invisible togetAllKeys, sosetSignalis never called for them; theSTORE_HASloops (reconcile.ts:209/:359) have the same gap. MeanwhileapplyState*has already swappedSTORE_VALUEtonext, so the stale node shadows the new value for direct reads too.Does this exist in Solid 1.x?
Exists in 1.x too — in a worse form. Verified against solid-js 1.9.14: 1.x
reconciledoesn't even merge symbol-keyed values (state[sym]stays at the old value aftersetState(reconcile({ [sym]: 2, a: 2 })); string keys update fine), so no notification question even arises. 2.0 half-fixed this — the value now merges — but subscribers of the symbol-keyed node are still never notified. Not a regression, but 2.0 already handles symbols in its other store paths (getAllKeys, set trap after #2769), so finishing the job in reconcile's diff loops is consistent.