Describe the bug
A tracked computation that reads query data THROUGH a createMemo(() => query.data) indirection
re-runs after a refetch — but reads the value from before the refetch, and is never notified
again, so its last observation stays stale permanently. At 6.0.0-rc.0 the same computation reads
the new value.
Narrowing, all measured at rc.1:
- An effect reading
query.data directly (no memo) observes the new value — the memo indirection
is the trigger.
- The same value change committed synchronously via
queryClient.setQueryData() is observed
through the memo too — the failure needs the refetch path, where the data projection's derive
returns a promise and the commit is asynchronous.
- The memo itself never recomputes across the refetch (consistent with the data node being one
stable store root reconciled in place), and after everything settles the memo's cached value is
=== a direct query.data read — at which point an UNTRACKED read through the memo returns the
NEW value. So the stale read happens at notify time: the effect re-runs before the new value is
observable through the memo, and no second notification arrives after it commits.
- Two pure-solid
createProjection mimics of the rc.1 data-node shape (a promise-returning
derive, a memo over the root leaf, an effect reading through the memo — with and without the
derive reading its own previous committed value) both pass on solid-js 2.0.0-rc.4, so this does
not look like a generic solid-js memo-over-projection defect, at least not in the documented
shape.
A memo over query.data is the natural shape of any wrapper hook that gates or narrows a query's
data before handing it to consumers, so this bites app code that never spells
createMemo(() => query.data) explicitly.
Your minimal, reproducible example
https://github.com/TylerRick/solid-query-stale-read-through-memo-repro
A git repo rather than a sandbox because the repro is a vitest run — four files, pnpm install
and one command.
function Probe() {
const query = useQuery(() => ({
queryKey: key,
queryFn: async () => ({ ...serverValue }),
}));
const data = createMemo(() => query.data);
createEffect(
() => data()?.video1,
(video1) => {
captured = video1;
},
);
return <div />;
}
// serverValue starts { video1: false }; after mount+settle:
// serverValue = { video1: true }; await queryClient.refetchQueries({ queryKey: key }); settle
// rc.0: effect re-runs, captured === true
// rc.1: effect re-runs, captured === false — and no further notification ever arrives
Steps to reproduce
- Mount a
useQuery, read one of its data properties in a tracked computation THROUGH a
createMemo(() => query.data).
- Let the first fetch settle, then
refetchQueries with the queryFn now returning a fresh object
with a changed value.
- The tracked computation re-runs but captures the previous value, and never re-runs again.
Expected behavior
The re-run observes the new value (as at 6.0.0-rc.0), or a second notification follows the commit.
Either way a subscriber's LAST observation should not be the superseded value.
How often does this bug happen?
Every time
Platform
- OS: Linux (x64)
- Node: 24.19.0
- jsdom (vitest) — client-side only, no SSR
Tanstack Query adapter
solid-query
TanStack Query version
@tanstack/solid-query 6.0.0-rc.1, with @tanstack/query-core 5.101.4 (rc.1's own exact
dependency, pinned via a direct dependency and a pnpm.overrides entry, so the query-core bump
that normally rides along with rc.1 is held constant). Clean at @tanstack/solid-query 6.0.0-rc.0
with the same query-core pin.
TypeScript version
n/a — the reproduction's .tsx is transpiled by vitest/vite-plugin-solid and never typechecked.
Additional context
solid-js / @solidjs/web 2.0.0-rc.4, @solidjs/testing-library 1.0.0-beta.2, vitest 3.
Found upgrading an app from rc.0: its wrapper hook returns a gate memo over query.data, so every
fine-grained subscriber downstream of the hook captured pre-refetch data forever after any
refetch. Reduced by subtracting from the failing app test — reconcile: 'id', deep(), the
nested data shape, cache priming, staleTime, and enabled were each removed with the failure
persisting.
Possibly related context: rc.1's rewrite of useBaseQuery onto Solid 2's native async model
(#11308), which replaced the resource machinery with a single createProjection data node.
Describe the bug
A tracked computation that reads query data THROUGH a
createMemo(() => query.data)indirectionre-runs after a refetch — but reads the value from before the refetch, and is never notified
again, so its last observation stays stale permanently. At 6.0.0-rc.0 the same computation reads
the new value.
Narrowing, all measured at rc.1:
query.datadirectly (no memo) observes the new value — the memo indirectionis the trigger.
queryClient.setQueryData()is observedthrough the memo too — the failure needs the refetch path, where the data projection's derive
returns a promise and the commit is asynchronous.
stable store root reconciled in place), and after everything settles the memo's cached value is
===a directquery.dataread — at which point an UNTRACKED read through the memo returns theNEW value. So the stale read happens at notify time: the effect re-runs before the new value is
observable through the memo, and no second notification arrives after it commits.
createProjectionmimics of the rc.1 data-node shape (a promise-returningderive, a memo over the root leaf, an effect reading through the memo — with and without the
derive reading its own previous committed value) both pass on solid-js 2.0.0-rc.4, so this does
not look like a generic solid-js memo-over-projection defect, at least not in the documented
shape.
A memo over
query.datais the natural shape of any wrapper hook that gates or narrows a query'sdata before handing it to consumers, so this bites app code that never spells
createMemo(() => query.data)explicitly.Your minimal, reproducible example
https://github.com/TylerRick/solid-query-stale-read-through-memo-repro
A git repo rather than a sandbox because the repro is a vitest run — four files,
pnpm installand one command.
Steps to reproduce
useQuery, read one of its data properties in a tracked computation THROUGH acreateMemo(() => query.data).refetchQuerieswith the queryFn now returning a fresh objectwith a changed value.
Expected behavior
The re-run observes the new value (as at 6.0.0-rc.0), or a second notification follows the commit.
Either way a subscriber's LAST observation should not be the superseded value.
How often does this bug happen?
Every time
Platform
Tanstack Query adapter
solid-query
TanStack Query version
@tanstack/solid-query6.0.0-rc.1, with@tanstack/query-core5.101.4 (rc.1's own exactdependency, pinned via a direct dependency and a
pnpm.overridesentry, so the query-core bumpthat normally rides along with rc.1 is held constant). Clean at
@tanstack/solid-query6.0.0-rc.0with the same query-core pin.
TypeScript version
n/a — the reproduction's
.tsxis transpiled by vitest/vite-plugin-solid and never typechecked.Additional context
solid-js / @solidjs/web 2.0.0-rc.4, @solidjs/testing-library 1.0.0-beta.2, vitest 3.
Found upgrading an app from rc.0: its wrapper hook returns a gate memo over
query.data, so everyfine-grained subscriber downstream of the hook captured pre-refetch data forever after any
refetch. Reduced by subtracting from the failing app test —
reconcile: 'id',deep(), thenested data shape, cache priming,
staleTime, andenabledwere each removed with the failurepersisting.
Possibly related context: rc.1's rewrite of
useBaseQueryonto Solid 2's native async model(#11308), which replaced the resource machinery with a single
createProjectiondata node.