Skip to content

solid-query 6.0.0-rc.1: removeQueries() on an actively observed query is immediately re-created and refetched #11350

Description

@TylerRick

Describe the bug

Calling queryClient.removeQueries() while a useQuery observer is mounted removes the entry and
then immediately brings it back: the cache emits removed followed by added, the observer is
torn down and re-attached, and the recreated entry starts a fresh fetch of the key that was just
removed. At 6.0.0-rc.0 the removal sticks (entry count 0, no further events, no fetch).

The practical consequence: a caller that removes entries to make them unreadable — for example an
identity/login boundary that must guarantee the previous user's data cannot be read — cannot make
the removal last. The entry is re-created immediately, and the automatic refetch repopulates the
removed key, under whatever key and queryFn the still-mounted observer holds.

Provenance controls in the repro pin down what does and does not happen at rc.1:

  • The old value is NOT retained: with the post-removal refetch parked on a never-resolving
    promise, the re-added entry sits 'pending'/'fetching' and getQueryData stays undefined.
  • The refetch is real: a queryFn returning 'v1' on the first call and 'v2' afterwards ends
    with getQueryData === 'v2' and a fetch count of 2, with staleTime ruling out an ordinary
    mount refetch.

If an active observer re-creating and refetching a removed query is intended in the rc.1 model, is
there a supported way to make removal stick — or at least be observable — while observers are
mounted?

Your minimal, reproducible example

https://github.com/TylerRick/solid-query-remove-queries-recreated-repro

A git repo rather than a sandbox because the repro is a vitest run — three files, pnpm install
and one command.

const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 60_000 } } });
const key = ['probe'];
let fetches = 0;
const queryFn = async () => (++fetches === 1 ? 'v1' : 'v2');

await queryClient.prefetchQuery({ queryKey: key, queryFn });

function Reader() {
	const query = useQuery(() => ({ queryKey: key, queryFn }));
	return <div>{String(query.data)}</div>;
}
// render <QueryClientProvider client={queryClient}><Reader /></QueryClientProvider>, settle

await queryClient.cancelQueries();
queryClient.removeQueries();
// settle 30ms
// rc.0: cache events […, 'removed'], 0 entries, getQueryData undefined, fetches === 1
// rc.1: […, 'removed', 'added', 'observerRemoved', 'observerAdded', 'updated', …], 1 entry,
//       getQueryData 'v2', fetches === 2

Steps to reproduce

  1. Prefetch a key, mount one useQuery observing it (staleTime high enough that the mount does
    not refetch).
  2. await queryClient.cancelQueries(); queryClient.removeQueries();
  3. Wait a tick and inspect queryClient.getQueryCache().getAll(), getQueryData, and the fetch
    count.

Expected behavior

removeQueries() leaves the cache without the entry, as at 6.0.0-rc.0 — or, if recreation by an
active observer is intended, at least does not silently refetch a key the caller just removed, and
gives the caller some way to observe/prevent the resurrection.

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: an identity-change boundary that cancels and removes all
queries, then gates UI on the removal being observable, never sees the entries gone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions