Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] repro hydrate() causes unhandled promise rejection with a throwing prefetchQuery #7867

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

alvarlagerlof
Copy link

@alvarlagerlof alvarlagerlof commented Aug 7, 2024

Debugging an issue where I see A query that was dehydrated as pending ended up rejecting. [${query?.queryHash}]: Error: server error; The error will be redacted in production builds logged, but my SSR render also returned a status code of 500.

Upon digging into the code, I think I found that hydrate() can cause an unhandled promise rejection from here when dehydrateQuery catches an error and returns a Promise.reject because a queryFn threw.

It seems like no tests are covering this, due to them ending before the rejection happens, but when I run the tests with the change in this PR, I get the following:

Test run ✔ nx run @tanstack/query-core:build [existing outputs match the cache, left as is] ✔ nx run @tanstack/query-persist-client-core:build [existing outputs match the cache, left as is] ✔ nx run @tanstack/react-query:build [existing outputs match the cache, left as is] ✔ nx run @tanstack/query-devtools:build [existing outputs match the cache, left as is] ✔ nx run @tanstack/react-query-persist-client:test:lib [existing outputs match the cache, left as is] ✔ nx run @tanstack/react-query-devtools:test:lib [existing outputs match the cache, left as is]

———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
✖ nx run @tanstack/react-query:test:lib
> @tanstack/[email protected] test:lib /Users/alvar/Code/query/packages/react-query
> vitest --retry=3

  Testing types with tsc and vue-tsc is an experimental feature.
  Breaking changes might not follow SemVer, please pin Vitest's version when using it.
  
   RUN  v2.0.5 /Users/alvar/Code/query/packages/react-query
        Coverage enabled with istanbul
  
   ✓ |@tanstack/react-query| src/__tests__/queryOptions.test-d.tsx  (18 tests)
   ✓ |@tanstack/react-query| src/__tests__/infiniteQueryOptions.test-d.tsx  (10 tests)
   ✓ |@tanstack/react-query| src/__tests__/useQueries.test-d.tsx  (6 tests)
   ✓ |@tanstack/react-query| src/__tests__/useInfiniteQuery.test-d.tsx  (7 tests)
   ✓ |@tanstack/react-query| src/__tests__/useQuery.test-d.tsx  (9 tests)
   ✓ |@tanstack/react-query| src/__tests__/useSuspenseQueries.test-d.tsx  (6 tests)
   ✓ |@tanstack/react-query| src/__tests__/suspense.test-d.tsx  (9 tests)
   ✓ |@tanstack/react-query| src/__tests__/prefetch.test-d.tsx  (5 tests)
  stderr | src/__tests__/prefetch.test.tsx > usePrefetchQuery > should let errors fall through and not refetch failed queries
  Error: Oops! Server error!
      at /Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:137:13 {
    [stack]: 'Error: Oops! Server error!\n' +
      '    at /Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:137:13',
    [message]: 'Oops! Server error!'
  }
  
  The above error occurred in the <Suspended> component:
  
      at Suspended (/Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:39:64)
      at Suspense
      at ErrorBoundary (/Users/alvar/Code/query/node_modules/.pnpm/[email protected][email protected]/node_modules/react-error-boundary/dist/react-error-boundary.development.esm.js:14:5)
      at App (/Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:126:29)
      at QueryClientProvider (/Users/alvar/Code/query/packages/react-query/src/QueryClientProvider.tsx:400:3)
  
  React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.
  
  stderr | src/__tests__/prefetch.test.tsx > usePrefetchQuery > should be able to recover from errors and try fetching again
  Error: Oops! Server error!
      at /Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:200:13 {
    [stack]: 'Error: Oops! Server error!\n' +
      '    at /Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:200:13',
    [message]: 'Oops! Server error!'
  }
  
  The above error occurred in the <Suspended> component:
  
      at Suspended (/Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:39:64)
      at Suspense
      at ErrorBoundary (/Users/alvar/Code/query/node_modules/.pnpm/[email protected][email protected]/node_modules/react-error-boundary/dist/react-error-boundary.development.esm.js:14:5)
      at App (/Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:204:47)
      at QueryClientProvider (/Users/alvar/Code/query/packages/react-query/src/QueryClientProvider.tsx:400:3)
  
  React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.
  
   ✓ |@tanstack/react-query| src/__tests__/useQueries.test.tsx  (19 tests) 673ms
   ✓ |@tanstack/react-query| src/__tests__/useMutation.test.tsx  (23 tests) 869ms
  stderr | src/__tests__/prefetch.test.tsx > usePrefetchInfiniteQuery > should prefetch an infinite query if query state does not exist
  Warning: Each child in a list should have a unique "key" prop.
  
  Check the render method of `Suspended`. See https://react.dev/link/warning-keys for more information.
      at div
      at Suspended (/Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:337:72)
      at Suspense
      at App (/Users/alvar/Code/query/packages/react-query/src/__tests__/prefetch.test.tsx:366:29)
      at QueryClientProvider (/Users/alvar/Code/query/packages/react-query/src/QueryClientProvider.tsx:400:3)
  
   ✓ |@tanstack/react-query| src/__tests__/HydrationBoundary.test.tsx  (7 tests) 180ms
   ✓ |@tanstack/react-query| src/__tests__/ssr-hydration.test.tsx  (3 tests) 127ms
   ✓ |@tanstack/react-query| src/__tests__/QueryResetErrorBoundary.test.tsx  (13 tests) 1842ms
   ✓ |@tanstack/react-query| src/__tests__/prefetch.test.tsx  (9 tests) 1971ms
   ✓ |@tanstack/react-query| src/__tests__/useInfiniteQuery.test.tsx  (26 tests) 2448ms
   ✓ |@tanstack/react-query| src/__tests__/useSuspenseQueries.test.tsx  (6 tests) 37ms
   ✓ |@tanstack/react-query| src/__tests__/useIsFetching.test.tsx  (5 tests) 350ms
   ✓ |@tanstack/react-query| src/__tests__/fine-grained-persister.test.tsx  (3 tests) 46ms
   ✓ |@tanstack/react-query| src/__tests__/useMutationState.test.tsx  (7 tests) 732ms
   ✓ |@tanstack/react-query| src/__tests__/ssr.test.tsx  (5 tests) 15ms
   ✓ |@tanstack/react-query| src/__tests__/QueryClientProvider.test.tsx  (4 tests) 62ms
   ✓ |@tanstack/react-query| src/__tests__/suspense.test.tsx  (22 tests) 10490ms
   ❯ |@tanstack/react-query| src/__tests__/useQuery.test.tsx  (139 tests | 1 failed) 10864ms
     × useQuery > should retry failed initialPromise on the client
       → Unable to find an element with the text: failure: redacted. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
  
  Ignored nodes: comments, script, style
  <body>
    <div>
      <div>
        <div>
          failure: 
        </div>
        <div>
          data: 
          client
        </div>
      </div>
    </div>
  </body>
  
  Ignored nodes: comments, script, style
  <html>
    <head />
    <body>
      <div>
        <div>
          <div>
            failure: 
          </div>
          <div>
            data: 
            client
          </div>
        </div>
      </div>
    </body>
  </html>
       → Unable to find an element with the text: failure: redacted. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
  
  Ignored nodes: comments, script, style
  <body>
    <div>
      <div>
        <div>
          failure: 
        </div>
        <div>
          data: 
          client
        </div>
      </div>
    </div>
  </body>
  
  Ignored nodes: comments, script, style
  <html>
    <head />
    <body>
      <div>
        <div>
          <div>
            failure: 
          </div>
          <div>
            data: 
            client
          </div>
        </div>
      </div>
    </body>
  </html>
       → Unable to find an element with the text: failure: redacted. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
  
  Ignored nodes: comments, script, style
  <body>
    <div>
      <div>
        <div>
          failure: 
        </div>
        <div>
          data: 
          client
        </div>
      </div>
    </div>
  </body>
  
  Ignored nodes: comments, script, style
  <html>
    <head />
    <body>
      <div>
        <div>
          <div>
            failure: 
          </div>
          <div>
            data: 
            client
          </div>
        </div>
      </div>
    </body>
  </html>
       → Unable to find an element with the text: failure: redacted. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
  
  Ignored nodes: comments, script, style
  <body>
    <div>
      <div>
        <div>
          failure: 
        </div>
        <div>
          data: 
          client
        </div>
      </div>
    </div>
  </body>
  
  Ignored nodes: comments, script, style
  <html>
    <head />
    <body>
      <div>
        <div>
          <div>
            failure: 
          </div>
          <div>
            data: 
            client
          </div>
        </div>
      </div>
    </body>
  </html>
  
  ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
  
   FAIL  |@tanstack/react-query| src/__tests__/useQuery.test.tsx > useQuery > should retry failed initialPromise on the client
   FAIL  |@tanstack/react-query| src/__tests__/useQuery.test.tsx > useQuery > should retry failed initialPromise on the client
   FAIL  |@tanstack/react-query| src/__tests__/useQuery.test.tsx > useQuery > should retry failed initialPromise on the client
   FAIL  |@tanstack/react-query| src/__tests__/useQuery.test.tsx > useQuery > should retry failed initialPromise on the client
  TestingLibraryElementError: Unable to find an element with the text: failure: redacted. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
  
  Ignored nodes: comments, script, style
  <body>
    <div>
      <div>
        <div>
          failure: 
        </div>
        <div>
          data: 
          client
        </div>
      </div>
    </div>
  </body>
  
  Ignored nodes: comments, script, style
  <html>
    <head />
    <body>
      <div>
        <div>
          <div>
            failure: 
          </div>
          <div>
            data: 
            client
          </div>
        </div>
      </div>
    </body>
  </html>
   ❯ Proxy.waitForWrapper ../../node_modules/.pnpm/@[email protected]/node_modules/@testing-library/dom/dist/wait-for.js:163:27
   ❯ src/__tests__/useQuery.test.tsx:6587:11
      6585| 
      6586|     const rendered = renderWithClient(clientQueryClient, <Page />)
      6587|     await waitFor(() => rendered.getByText('failure: redacted'))
         |           ^
      6588|     await waitFor(() => rendered.getByText('data: client'))
      6589|     expect(count).toBe(1)
  
  ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/4]⎯
  
  ⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯
  
  Vitest caught 4 unhandled errors during the test run.
  This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.
  
  ⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
  Error: redacted
   ❯ ../query-core/src/hydration.ts:90:31
  
  This error originated in "src/__tests__/useQuery.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
  The latest test that might've caused the error is "should retry failed initialPromise on the client". It might mean one of the following:
  - The error was thrown, while Vitest was running this test.
  - If the error occurred after the test had been completed, this was the last documented test before it was thrown.
  
  ⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
  Error: redacted
   ❯ ../query-core/src/hydration.ts:90:31
  
  This error originated in "src/__tests__/useQuery.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
  The latest test that might've caused the error is "should retry failed initialPromise on the client". It might mean one of the following:
  - The error was thrown, while Vitest was running this test.
  - If the error occurred after the test had been completed, this was the last documented test before it was thrown.
  
  ⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
  Error: redacted
   ❯ ../query-core/src/hydration.ts:90:31
  
  This error originated in "src/__tests__/useQuery.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
  The latest test that might've caused the error is "should retry failed initialPromise on the client". It might mean one of the following:
  - The error was thrown, while Vitest was running this test.
  - If the error occurred after the test had been completed, this was the last documented test before it was thrown.
  
  ⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
  Error: redacted
   ❯ ../query-core/src/hydration.ts:90:31
  
  This error originated in "src/__tests__/useQuery.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
  The latest test that might've caused the error is "should retry failed initialPromise on the client". It might mean one of the following:
  - The error was thrown, while Vitest was running this test.
  - If the error occurred after the test had been completed, this was the last documented test before it was thrown.
  ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
  
   Test Files  1 failed | 22 passed (23)
        Tests  1 failed | 360 passed (361)
  Type Errors  no errors
       Errors  4 errors
     Start at  16:52:31
     Duration  15.39s (transform 1.15s, setup 9.32s, collect 4.87s, tests 30.71s, environment 18.06s, prepare 1.41s, typecheck 2.72s)
  
   ELIFECYCLE  Command failed with exit code 1.

———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

NX Ran target test:lib for 3 projects and 4 tasks they depend on (19s)

✔ 6/7 succeeded [6 read from cache]

✖ 1/7 targets failed, including the following:

  - nx run @tanstack/react-query:test:lib

View structured, searchable error logs at https://nx.app/runs/yruFhd2Ecu

 ELIFECYCLE  Command failed with exit code 1.

@alvarlagerlof alvarlagerlof changed the title [WIP] repro hydrate() throws after test completion [WIP] repro hydrate() causes unhandled promise rejection with a throwing prefetchQuery Aug 7, 2024
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.

1 participant