…s queries still fetch
fetchOptimistic builds the query from the observer's options but then calls query.fetch() without them. QueryCache.build returns an existing query without applying options, so a query that was rebuilt without a queryFn - by broadcastQueryClient from a cross-tab message, or hydrated - throws Missing queryFn when a suspending observer fetches it before any observer has attached: the fallback at the top of fetch() only looks at already-attached observers, and there are none yet in this path.
Reported through query-broadcast-client-experimental: when a query is removed and re-added cross-tab, the rebuilt query stays without a queryFn if the other tab's fetch never succeeds, and a mounted useSuspenseQuery crashes with Missing queryFn on its next optimistic fetch instead of fetching with its own options.
The regression test reproduces that sequence: observer bound -> query removed -> rebuilt from key+hash only -> fetchOptimistic. It fails with Missing queryFn before this change and succeeds after. Full queryObserver suite (76) and broadcast client suite (13) pass.
Fixes TanStack#12129
fetchOptimisticbuilds the query from the observer's defaulted options but then callsquery.fetch()without them. SinceQueryCache.buildreturns an existing query without applying options, a query that already exists without aqueryFnthrowsMissing queryFnhere: the fallback at the top offetch()only looks at already-attached observers, and in this path none are attached yet - a suspending observer is still bound to the previous query object and only re-binds in a later effect.This is reachable through
broadcastQueryClient(reported in #12129): a query removed in one tab is rebuilt in the other from{ queryKey, queryHash }only; if the other tab's fetch never succeeds, no data-bearing update follows, and a mounteduseSuspenseQueryfor that key crashes withMissing queryFninstead of fetching with its own options. Hydrated andsetQueryData-created queries hit the same window.The fix passes the defaulted options to
fetch(), whosesetOptionssupplies the queryFn. In the normal path this is a no-op (the freshly built query was constructed with exactly these options).Regression test reproduces the reported sequence (observer bound -> query removed -> rebuilt from key+hash only ->
fetchOptimistic): fails withMissing queryFnbefore, succeeds after. FullqueryObserversuite (76/76) andquery-broadcast-client-experimentalsuite (13/13) pass.Fixes #12129
Summary by CodeRabbit