From 33419050e702680d191f5d978f6824877db77af3 Mon Sep 17 00:00:00 2001 From: TkDodo Date: Wed, 5 Nov 2025 14:20:24 +0100 Subject: [PATCH 1/2] fix(core): only attach .then and .catch onto a promise if it gets dehydrated --- packages/query-core/src/hydration.ts | 42 +++++++++++++++------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index 4b8c614677..c75d8ee332 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -79,25 +79,29 @@ function dehydrateQuery( serializeData: TransformerFn, shouldRedactErrors: (error: unknown) => boolean, ): DehydratedQuery { - const promise = query.promise?.then(serializeData).catch((error) => { - if (!shouldRedactErrors(error)) { - // Reject original error if it should not be redacted - return Promise.reject(error) - } - // If not in production, log original error before rejecting redacted error - if (process.env.NODE_ENV !== 'production') { - console.error( - `A query that was dehydrated as pending ended up rejecting. [${query.queryHash}]: ${error}; The error will be redacted in production builds`, - ) - } - return Promise.reject(new Error('redacted')) - }) + const dehydratePromise = () => { + const promise = query.promise?.then(serializeData).catch((error) => { + if (!shouldRedactErrors(error)) { + // Reject original error if it should not be redacted + return Promise.reject(error) + } + // If not in production, log original error before rejecting redacted error + if (process.env.NODE_ENV !== 'production') { + console.error( + `A query that was dehydrated as pending ended up rejecting. [${query.queryHash}]: ${error}; The error will be redacted in production builds`, + ) + } + return Promise.reject(new Error('redacted')) + }) + + // Avoid unhandled promise rejections + // We need the promise we dehydrate to reject to get the correct result into + // the query cache, but we also want to avoid unhandled promise rejections + // in whatever environment the prefetches are happening in. + promise?.catch(noop) - // Avoid unhandled promise rejections - // We need the promise we dehydrate to reject to get the correct result into - // the query cache, but we also want to avoid unhandled promise rejections - // in whatever environment the prefetches are happening in. - promise?.catch(noop) + return promise + } return { dehydratedAt: Date.now(), @@ -110,7 +114,7 @@ function dehydrateQuery( queryKey: query.queryKey, queryHash: query.queryHash, ...(query.state.status === 'pending' && { - promise, + promise: dehydratePromise(), }), ...(query.meta && { meta: query.meta }), } From 033c868633938422aa24279fa0ccf8281e98cb64 Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Wed, 5 Nov 2025 16:30:58 +0100 Subject: [PATCH 2/2] Fix promise handling in core for dehydrated states Ensure .then and .catch are only attached to dehydrated promises. --- .changeset/little-berries-search.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/little-berries-search.md diff --git a/.changeset/little-berries-search.md b/.changeset/little-berries-search.md new file mode 100644 index 0000000000..1c85b08f08 --- /dev/null +++ b/.changeset/little-berries-search.md @@ -0,0 +1,5 @@ +--- +"@tanstack/query-core": patch +--- + +fix(core): only attach .then and .catch onto a promise if it gets dehydrated