remix-run / remix

Build Better Websites. Create modern, resilient user experiences with web fundamentals.
https://remix.run
MIT License
29.72k stars 2.5k forks source link

"Expected fetch contoller" invariant failure #10057

Open gforro opened 2 weeks ago

gforro commented 2 weeks ago

Reproduction

https://stackblitz.com/~/github.com/gforro/remix-fetchers

Use cases which are probably bugs:

A: Fetcher in parent route gets to a for ever "loading" state

  1. Open the application and wait for fetcher in the header to finish data loading
  2. Submit the "Fetcher form" with 100ms response time
  3. Wait for the loading state of the submission (1 second for example) and click on "Go to Page 2" => fetcher in header is cancelled and a new load is executed
  4. Click again the "Go to Page 2" link => "Expected fetch controller" invariant failure is logged to the console
  5. User is navigated to Page 2 and the fetcher in the Header stays in "loading" state for ever

B: Fetcher in parent route gets to a for ever "loading" state

  1. Open the application and wait for fetcher in the header to finish data loading
  2. Submit the "Fetcher form" with the default 2000ms response time
  3. Click on the "Go to Page 2" immediately (in the submitting phase) => fetcher gets to "loading" state after the click, the application waits for the submission to be finished and navigates the user to Page 2
  4. Click the "Go to Page 1" immediately (while the Header fetcher is in loading state) => "Expected fetch controller" invariant failure is logged to the console
  5. User is navigated back to Page 1 and the fetcher in the Header stays in "loading" state for ever

Another use cases, which seems to be strange:

C: Fetcher in parent route blocks navigation after Form submission

  1. Open the application and wait for fetcher in the header to finish data loading
  2. Submit the "Form with navigation" with the default 2000ms response time
  3. Click on the "Go to Page 2" when the form state changes to "loading..." => the fetcher in the Header is cancelled and revalidated
  4. Click on the "Go to Page 2" again while the navigation state is "loading..." => the fetcher in the Header is cancelled and revalidated
  5. Click on the "Go to Page 2" again and again and again.... => the fetcher is the Header is always cancelled and revalidated

D: Fetcher in parent route blocks navigation after fetcher Form submission

  1. Open the application
  2. Click on "Mount" in the fetcher fieldset => fetcher is mounted to Page 1
  3. Wait for the fetchers to get idle
  4. Submit the "Fetcher form" with 100ms response time
  5. Wait for the loading state of the submission (1 second for example) and click on "Go to Page 2" => fetcher in header is cancelled and a new load is executed
  6. Click again the "Go to Page 2" link => fetcher in the header is cancelled and a new load is executed
  7. Keep clicking the "Go to Page 2" link => fetcher in the header is cancelled and a new load is executed and after a while (10-20 clicks) the "Expected fetch controller" invariant failure is logged to the console
  8. User is navigated to Page 2 and the fetcher in the Header stays in "loading" state for ever

Interesting that the application in case D behaves differently like in case A - they are similar and difference is the present of a fetcher in the child route. If there is a fetcher in the child route where the Fetcher form submission happened, then the navigation to Page 2 is blocked for a longer time (there is more successful revalidations of the Header fetcher but at use case ends with the very same invariant failure - just later.

System Info

See Stackblitcz. The problem also present in my Mac:

System:
    OS: macOS 14.7
    CPU: (10) arm64 Apple M1 Max
    Memory: 54.81 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.14.0 - ~/.nvm/versions/node/v20.14.0/bin/node
    Yarn: 1.22.22 - ~/.nvm/versions/node/v20.14.0/bin/yarn
    npm: 10.7.0 - ~/.nvm/versions/node/v20.14.0/bin/npm
    pnpm: 8.15.9 - ~/.nvm/versions/node/v20.14.0/bin/pnpm
  Browsers:
    Chrome: 129.0.6668.90
    Safari: 18.0
  npmPackages:
    @remix-run/dev: * => 2.12.1
    @remix-run/node: * => 2.12.1
    @remix-run/react: * => 2.12.1
    @remix-run/serve: * => 2.12.1
    vite: ^5.1.0 => 5.4.7

Used Package Manager

npm

Expected Behavior

I have expected to not block navigation when a fetcher in the parent route is revalidated because of a form submission in a child route. I have also not expected to get invariant failures when playing with fetchers and to not get a "for ever" loading state for a fetcher.

Actual Behavior

Navigation is blocked if there is a fetcher in the parent route which is revalidated because of a form submission in the child route. This problem is noticeable when there are longer response times (I know that response time should be around 200ms but it i not always the case unfortunately)

brophdawg11 commented 2 weeks ago

I believe these are duplicates of this issue in RR which has been fixed and will be available in an upcoming release: https://github.com/remix-run/react-router/issues/12049

gforro commented 2 weeks ago

Thanks @brophdawg11 for the reaction. It might be the same (I was not able to find that issue event I have tried to find a similar issue). The issue mentioned no runtime error, but there is one - the sticked "loading" state of fetchers after the failed invariant. Also fetchers stops to be revalidated after that error.

oyeesam commented 1 week ago

@brophdawg11 any alternative fixes, until upcoming release ?

brophdawg11 commented 1 week ago

@gforro Remix 2.13.0-pre.0 is out - would you like to test your scenarios against that and let us know if that helps?

I have expected to not block navigation when a fetcher in the parent route is revalidated because of a form submission in a child route.

I think this expectation is incorrect - when a submission navigation occurs, it waits for all active loaders to be revalidated before proceeding - this includes all route loaders and all fetcher.load calls.

With that in mind, would you be able to create individual minimal repros of any remaining issues on 2.13.0-pre.0? I'd be happy to take a look but the conglomerate app showing off 4 different scenarios is a little confusing when trying to hone in on a singular issue.