Skip to content

fix(query-core): fix hydration bugs for already resolved promises#10444

Merged
Ephem merged 9 commits intoTanStack:mainfrom
Ephem:fredrik/fix-resolved-promise-hydration
Apr 23, 2026
Merged

fix(query-core): fix hydration bugs for already resolved promises#10444
Ephem merged 9 commits intoTanStack:mainfrom
Ephem:fredrik/fix-resolved-promise-hydration

Conversation

@Ephem
Copy link
Copy Markdown
Collaborator

@Ephem Ephem commented Apr 10, 2026

🎯 Changes

Fixes #9642

This PR fixes and adds tests for two different bugs that would both cause queries to incorrectly jump into the fetching/pending state on hydration.

This would happen for queries that were prefetched without awaiting, like so: void queryClient.prefetchQuery(...) and then dehydrated, but where the promise would resolve before the hydration would happen. The query state in the hydration would be status: 'pending', since that's the status on the server at the moment of hydration, but when hydrating we should put them into the 'successful' state since we already have data.

First bug is that we did this for new queries, but not when queries already existed in the cache.

The second bug is that for both cases, we also still called query.fetch with an initialPromise, which would briefly emit a fetching state. We did this to set up a retryer and I even wrote a comment in the code that this was necessary even for queries that already had data, but I've since reconsidered. The retryer is optional, so if the query is already in a successful state, I don't think we need to do that for either new or existing queries and removing it shows no failing tests. This is a controversial part of the PR though and I'm happy for pushback.

If we need to keep the data in sync with the promise in the retryer, we already have a problem with that when people call query.setData, since we don't do anything with the retryer in those situations either.

Note that the promise we return from useQuery etc is different, that comes from the observer, not directly from the query.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes

    • Hydration no longer leaves queries backed by already-resolved or synchronously-resolved promises briefly in a pending/fetching state; such queries resolve to success immediately.
  • Tests

    • Added coverage for rehydration with synchronously-resolved promises to ensure correct cache status transitions and prevent regressions.
  • Chores

    • Added a patch release changeset documenting the hydration fix.

Ephem added 4 commits April 10, 2026 13:50
Implements failing test for incorrect pending status when hydrating already resolved promises and query already exists in the cache.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2465a54d-763d-4451-9972-0212c446e5c0

📥 Commits

Reviewing files that changed from the base of the PR and between 27e3412 and 652375e.

📒 Files selected for processing (1)
  • packages/query-core/src/__tests__/hydration.test.tsx

📝 Walkthrough

Walkthrough

Hydration behavior was changed so dehydrated queries whose promises already resolved are treated as successful; retryer creation and query.fetch calls are skipped for synchronously-resolved thenables. Tests and a changeset were added to cover streaming/hydration synchronous-thenable scenarios.

Changes

Cohort / File(s) Summary
Changeset
​.changeset/shy-wings-buy.md
Added a patch changeset for @tanstack/query-core documenting the hydration fix for synchronously-resolved promises.
Hydration Tests
packages/query-core/src/__tests__/hydration.test.tsx
Added three tests covering React streaming / synchronous-thenable hydration ensuring no transient pending/fetching states or intermediate fetching updates are emitted.
Hydration Logic
packages/query-core/src/hydration.ts
Adjusted merge logic to promote dehydrated pending states with defined data to success (without overriding an actively fetching fetchStatus), and avoid creating a retryer or calling query.fetch when the dehydrated promise resolved synchronously.

Sequence Diagram(s)

sequenceDiagram
  participant Server
  participant DehydratedState
  participant Client
  participant QueryCache
  participant Retryer

  Server->>DehydratedState: prefetch/create query (status: pending, promise)
  DehydratedState-->>Client: send dehydrated payload
  Client->>QueryCache: hydrate(payload)

  alt promise resolved synchronously
    QueryCache->>QueryCache: set data, set status -> success
    Note right of QueryCache: do NOT create Retryer
  else promise still pending/asynchronous
    QueryCache->>Retryer: create Retryer to manage fetch
    Retryer->>QueryCache: update fetchStatus -> fetching
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I nibbled on thenables in the dew-lit glade,
Found carrots ready — no frantic parade.
Hydration hummed soft, no fetching surprise,
Cache kept its calm beneath morning skies. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: fixing hydration bugs for already resolved promises, which is the core objective of the PR.
Description check ✅ Passed The PR description comprehensively covers all required sections from the template: detailed changes with motivation, marked checklist items, and release impact with changeset confirmation.
Linked Issues check ✅ Passed The code changes directly address issue #9642 by fixing both hydration bugs: handling existing queries in cache [hydration.ts] and preventing incorrect fetch calls for resolved promises [hydration.ts, tests].
Out of Scope Changes check ✅ Passed All changes are directly in scope: hydration logic fixes, regression tests, and a changeset file, all aligned with the stated objectives of fixing hydration race conditions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Apr 10, 2026

View your CI Pipeline Execution ↗ for commit 652375e

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 4m 25s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-23 13:51:31 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 10, 2026

More templates

@tanstack/angular-query-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-experimental@10444

@tanstack/eslint-plugin-query

npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@10444

@tanstack/preact-query

npm i https://pkg.pr.new/@tanstack/preact-query@10444

@tanstack/preact-query-devtools

npm i https://pkg.pr.new/@tanstack/preact-query-devtools@10444

@tanstack/preact-query-persist-client

npm i https://pkg.pr.new/@tanstack/preact-query-persist-client@10444

@tanstack/query-async-storage-persister

npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@10444

@tanstack/query-broadcast-client-experimental

npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@10444

@tanstack/query-core

npm i https://pkg.pr.new/@tanstack/query-core@10444

@tanstack/query-devtools

npm i https://pkg.pr.new/@tanstack/query-devtools@10444

@tanstack/query-persist-client-core

npm i https://pkg.pr.new/@tanstack/query-persist-client-core@10444

@tanstack/query-sync-storage-persister

npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@10444

@tanstack/react-query

npm i https://pkg.pr.new/@tanstack/react-query@10444

@tanstack/react-query-devtools

npm i https://pkg.pr.new/@tanstack/react-query-devtools@10444

@tanstack/react-query-next-experimental

npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@10444

@tanstack/react-query-persist-client

npm i https://pkg.pr.new/@tanstack/react-query-persist-client@10444

@tanstack/solid-query

npm i https://pkg.pr.new/@tanstack/solid-query@10444

@tanstack/solid-query-devtools

npm i https://pkg.pr.new/@tanstack/solid-query-devtools@10444

@tanstack/solid-query-persist-client

npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@10444

@tanstack/svelte-query

npm i https://pkg.pr.new/@tanstack/svelte-query@10444

@tanstack/svelte-query-devtools

npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@10444

@tanstack/svelte-query-persist-client

npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@10444

@tanstack/vue-query

npm i https://pkg.pr.new/@tanstack/vue-query@10444

@tanstack/vue-query-devtools

npm i https://pkg.pr.new/@tanstack/vue-query-devtools@10444

commit: 652375e

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/query-core/src/hydration.ts`:
- Around line 239-247: The current hydration always forces status: 'success'
whenever data !== undefined, which wipes error states; restrict that override to
only when the existing query was a resolved pending promise by adding a guard
(e.g., compute an existingQueryIsPending boolean by checking the existing
query's status === 'pending') and apply the status: 'success' branch only when
data !== undefined && existingQueryIsPending (keeping the existing fetchStatus
preservation via existingQueryIsFetching). Locate the block in hydration.ts
where data and existingQueryIsFetching are used and add the pending-status check
before setting status: 'success'.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 816634ee-3ab7-4323-b7ac-8b69ccf55c9d

📥 Commits

Reviewing files that changed from the base of the PR and between d36ece2 and 3485052.

📒 Files selected for processing (3)
  • .changeset/shy-wings-buy.md
  • packages/query-core/src/__tests__/hydration.test.tsx
  • packages/query-core/src/hydration.ts

Comment thread packages/query-core/src/hydration.ts Outdated
@afurm
Copy link
Copy Markdown

afurm commented Apr 11, 2026

Good regression tests for this hydration edge case. A few observations:

On the syncData check in fetch: The new condition that prevents setting up a retryer when data is synchronously available makes sense — if the promise already resolved, we do not need retry logic. But does this interact with cacheTime or staleTime options? If a query is re-hydrated with sync data, goes stale, and then the user triggers a refetch, will the retryer be set up correctly then?

On preserving fetchStatus during re-hydration: The logic that preserves fetchStatus if the existing query is actively fetching is correct. But what if the existing query was fetching stale data and the dehydrated data is fresher? Would that cause a brief flash of incorrect fetch status before the next update?

On the test setup: The pattern to override promise.then to simulate synchronous resolution is clever but quite invasive. Have you considered using a microtask or Promise.resolve().then() instead to simulate the synchronous-thenable case more naturally without mutating the promise?

@Ephem
Copy link
Copy Markdown
Collaborator Author

Ephem commented Apr 23, 2026

@afurm

will the retryer be set up correctly then

Yes. The logic whether to revalidate lies elsewhere, if that elsewhere triggers a fetch, that will set up the retryer.

But what if the existing query was fetching stale data and the dehydrated data is fresher?

If a fetch is ongoing on the client, it's very likely to fetch fresher data than what was in a dehydrated query, so this is a tradeoff I'm willing to live with. 😄

Have you considered using a microtask or Promise.resolve().then() instead

The whole point is that it needs to be fully synchronous, so no.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/query-core/src/hydration.ts (1)

213-215: ⚠️ Potential issue | 🟠 Major

Preserve freshness when promoting synchronously resolved pending queries.

The sync-data path now skips query.fetch, so the success dispatch that would normally update dataUpdatedAt never runs. When state.status === 'pending', the serialized state can still carry dataUpdatedAt: 0; promoting it to success with that timestamp makes the hydrated data stale immediately and can regress an existing query even though hasNewerSyncData selected it as newer.

🐛 Proposed fix
       const syncData = promise ? tryResolveSync(promise) : undefined
       const rawData = state.data === undefined ? syncData?.data : state.data
       const data = rawData === undefined ? rawData : deserializeData(rawData)
+      const shouldPromoteResolvedPendingQuery =
+        state.status === 'pending' && data !== undefined
+      const dataUpdatedAt = shouldPromoteResolvedPendingQuery
+        ? (state.dataUpdatedAt || dehydratedAt || Date.now())
+        : state.dataUpdatedAt
 
       let query = queryCache.get(queryHash)
       const existingQueryIsPending = query?.state.status === 'pending'
       const existingQueryIsFetching = query?.state.fetchStatus === 'fetching'
@@
           query.setState({
             ...serializedState,
             data,
+            dataUpdatedAt,
             // If the query was pending at the moment of dehydration, but resolved to have data
             // before hydration, we can assume the query should be hydrated as successful.
@@
             ...state,
             data,
+            dataUpdatedAt,
             fetchStatus: 'idle',
             // Like above, if the query was pending at the moment of dehydration but has data,

Also applies to: 235-250, 266-275, 280-289

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/query-core/src/hydration.ts` around lines 213 - 215, When promoting
synchronously-resolved pending queries (the code path that uses syncData from
tryResolveSync(promise) and assigns rawData/data via deserializeData), preserve
freshness by ensuring dataUpdatedAt is set to a current timestamp instead of
carrying through a stale serialized value (e.g., 0). Specifically, when
state.status === 'pending' and syncData exists (or rawData came from syncData),
set dataUpdatedAt = syncData.dataUpdatedAt ?? Date.now() (or at minimum
Date.now()) before returning/using the promoted success state; apply the same
change to the other sync-resolution blocks referenced (around the other ranges)
so promotion never downgrades freshness.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/query-core/src/hydration.ts`:
- Around line 213-215: When promoting synchronously-resolved pending queries
(the code path that uses syncData from tryResolveSync(promise) and assigns
rawData/data via deserializeData), preserve freshness by ensuring dataUpdatedAt
is set to a current timestamp instead of carrying through a stale serialized
value (e.g., 0). Specifically, when state.status === 'pending' and syncData
exists (or rawData came from syncData), set dataUpdatedAt =
syncData.dataUpdatedAt ?? Date.now() (or at minimum Date.now()) before
returning/using the promoted success state; apply the same change to the other
sync-resolution blocks referenced (around the other ranges) so promotion never
downgrades freshness.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5fb7dd8e-b9fd-4a0f-aeac-b4634746b80e

📥 Commits

Reviewing files that changed from the base of the PR and between 3485052 and 1f685dd.

📒 Files selected for processing (1)
  • packages/query-core/src/hydration.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/query-core/src/hydration.ts (2)

213-215: ⚠️ Potential issue | 🟠 Major

Set dataUpdatedAt when promoting resolved pending data to success.

Line 243 and Line 273 can turn a pending dehydrated query into success, but both branches keep the pending state’s dataUpdatedAt—often 0. In the existing-query path, this can even move the timestamp backwards after hasNewerSyncData decided the payload is newer, causing fresh hydrated data to look stale/refetchable.

🐛 Proposed fix
       const syncData = promise ? tryResolveSync(promise) : undefined
       const rawData = state.data === undefined ? syncData?.data : state.data
       const data = rawData === undefined ? rawData : deserializeData(rawData)
+      const resolvedPendingQuery =
+        state.status === 'pending' && data !== undefined
+      const resolvedPendingDataUpdatedAt = resolvedPendingQuery
+        ? (dehydratedAt ?? Date.now())
+        : state.dataUpdatedAt
 
       let query = queryCache.get(queryHash)
@@
-            ...(state.status === 'pending' &&
-              data !== undefined && {
+            ...(resolvedPendingQuery && {
+              dataUpdatedAt: resolvedPendingDataUpdatedAt,
               status: 'success' as const,
               // Preserve existing fetchStatus if the existing query is actively fetching.
               ...(!existingQueryIsFetching && {
                 fetchStatus: 'idle' as const,
               }),
             }),
@@
           {
             ...state,
             data,
             fetchStatus: 'idle',
             // Like above, if the query was pending at the moment of dehydration but has data,
             // we can assume it should be hydrated as successful.
-            status:
-              state.status === 'pending' && data !== undefined
-                ? 'success'
-                : state.status,
+            dataUpdatedAt: resolvedPendingDataUpdatedAt,
+            status: resolvedPendingQuery ? 'success' : state.status,
           },

Also applies to: 235-250, 267-275

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/query-core/src/hydration.ts` around lines 213 - 215, When promoting
a pending dehydrated query to success using syncData from tryResolveSync, ensure
you update the state's dataUpdatedAt instead of preserving the old pending
timestamp; modify the branches that compute data (where syncData, rawData, data
are used and where hasNewerSyncData is consulted) to set dataUpdatedAt =
syncData?.updatedAt ?? Date.now() when syncData is applied so hydrated data gets
a current timestamp and doesn't appear stale.

217-250: ⚠️ Potential issue | 🟠 Major

Treat paused queries as active fetches.

Line 219 only preserves fetching, but paused is also a non-idle active fetch state in Query.fetch(). A paused existing query can be reset to idle at Line 248 and pass the fetch guard at Line 286, losing paused state or creating retryer inconsistencies.

🐛 Proposed fix
       let query = queryCache.get(queryHash)
       const existingQueryIsPending = query?.state.status === 'pending'
-      const existingQueryIsFetching = query?.state.fetchStatus === 'fetching'
+      const existingQueryHasActiveFetch =
+        query !== undefined && query.state.fetchStatus !== 'idle'
@@
-                // Preserve existing fetchStatus if the existing query is actively fetching.
-                ...(!existingQueryIsFetching && {
+                // Preserve existing fetchStatus if the existing query has an active fetch.
+                ...(!existingQueryHasActiveFetch && {
                   fetchStatus: 'idle' as const,
                 }),
@@
         !syncData &&
         !existingQueryIsPending &&
-        !existingQueryIsFetching &&
+        !existingQueryHasActiveFetch &&
         // Only hydrate if dehydration is newer than any existing data,

Also applies to: 280-289

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/query-core/src/hydration.ts` around lines 217 - 250, The code only
treats fetchStatus === 'fetching' as an active fetch when computing
existingQueryIsFetching and later preserving fetchStatus in query.setState;
change those checks to treat 'paused' the same as 'fetching' (e.g.,
existingQueryIsFetching -> existingQueryIsActiveFetch = query?.state.fetchStatus
=== 'fetching' || query?.state.fetchStatus === 'paused') and use that new
boolean wherever the code currently gates preserving fetchStatus (including the
similar block later around the other hydration branch), so paused queries are
preserved and not reset to 'idle'.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/query-core/src/hydration.ts`:
- Around line 213-215: When promoting a pending dehydrated query to success
using syncData from tryResolveSync, ensure you update the state's dataUpdatedAt
instead of preserving the old pending timestamp; modify the branches that
compute data (where syncData, rawData, data are used and where hasNewerSyncData
is consulted) to set dataUpdatedAt = syncData?.updatedAt ?? Date.now() when
syncData is applied so hydrated data gets a current timestamp and doesn't appear
stale.
- Around line 217-250: The code only treats fetchStatus === 'fetching' as an
active fetch when computing existingQueryIsFetching and later preserving
fetchStatus in query.setState; change those checks to treat 'paused' the same as
'fetching' (e.g., existingQueryIsFetching -> existingQueryIsActiveFetch =
query?.state.fetchStatus === 'fetching' || query?.state.fetchStatus ===
'paused') and use that new boolean wherever the code currently gates preserving
fetchStatus (including the similar block later around the other hydration
branch), so paused queries are preserved and not reset to 'idle'.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e452fb36-302a-4618-91ba-a816173070fb

📥 Commits

Reviewing files that changed from the base of the PR and between 1f685dd and 878f085.

📒 Files selected for processing (1)
  • packages/query-core/src/hydration.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/query-core/src/__tests__/hydration.test.tsx (1)

1394-1448: Nit: async without await.

This test is declared async but never awaits anything — everything it asserts happens synchronously during hydrate(...). The function can simply be non-async (and the trailing resolvePrefetch?.('server data') at line 1419 is also effectively a no-op since no consumer of prefetchPromise exists before the dehydrate call and the overridden then at 1421 short-circuits any await on the dehydrated promise). Keeping it truly sync makes the "must hydrate synchronously" intent clearer, matching the companion test at 1350.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/query-core/src/__tests__/hydration.test.tsx` around lines 1394 -
1448, Remove the unnecessary async marker from the test "should set status to
success when rehydrating an existing pending query with a synchronously resolved
promise" and any unused async-related artifacts: make the test function
non-async, remove/comment out any unused await usage (there are none), and keep
the synchronous resolution of prefetchPromise via resolvePrefetch and the
overridden dehydrated.queries[0].promise.then behavior as-is; ensure the test
still calls serverQueryClient.prefetchQuery, dehydrate(...),
hydrate(clientQueryClient, dehydrated), and asserts
clientQueryClient.getQueryData(key) === 'server data' and query.state.status ===
'success'.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/query-core/src/__tests__/hydration.test.tsx`:
- Around line 1394-1505: Three new tests use test(...) instead of the project's
preferred it(...), causing ESLint vitest/consistent-test-it failures; rename the
three occurrences of test('should set status to success when rehydrating an
existing pending query with a synchronously resolved promise', ...),
test('should not transition to a fetching/pending state when hydrating an
already resolved promise into a new query', ...), and test('should not
transition to a fetching/pending state when hydrating an already resolved
promise into an existing query', ...) to use it(...) with the exact same
descriptions and bodies so the tests remain identical but conform to the
consistent-it rule.

---

Nitpick comments:
In `@packages/query-core/src/__tests__/hydration.test.tsx`:
- Around line 1394-1448: Remove the unnecessary async marker from the test
"should set status to success when rehydrating an existing pending query with a
synchronously resolved promise" and any unused async-related artifacts: make the
test function non-async, remove/comment out any unused await usage (there are
none), and keep the synchronous resolution of prefetchPromise via
resolvePrefetch and the overridden dehydrated.queries[0].promise.then behavior
as-is; ensure the test still calls serverQueryClient.prefetchQuery,
dehydrate(...), hydrate(clientQueryClient, dehydrated), and asserts
clientQueryClient.getQueryData(key) === 'server data' and query.state.status ===
'success'.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 03783648-8519-4e2d-a4e2-dc7cc1142db1

📥 Commits

Reviewing files that changed from the base of the PR and between 878f085 and 27e3412.

📒 Files selected for processing (1)
  • packages/query-core/src/__tests__/hydration.test.tsx

Comment thread packages/query-core/src/__tests__/hydration.test.tsx Outdated
@Ephem Ephem merged commit 1bb0d23 into TanStack:main Apr 23, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Race condition causing hydration error when streaming with server components

3 participants