swr icon indicating copy to clipboard operation
swr copied to clipboard

error thrown in mutate bubbles up to error of useSWR hook

Open felixroos opened this issue 2 years ago • 4 comments

Bug report

Description / Observed Behavior

What kind of issues did you encounter with SWR?

When calling mutate with a function as 2nd argument and an error is thrown inside that function, the error will bubble up to error returned by useSWR.

Expected Behavior

How did you expect SWR to behave here?

The error should not bubble up, as it mixes up data fetching with data mutation errors.

As written in the API Options

error: error thrown by fetcher (or undefined)

Correct would be error thrown by fetcher or inside mutate (or undefined)

I don't know if this is an intentional design decision or just a bug.

Repro Steps / Code Example

Or share your code snippet or a CodeSandbox link is also appreciated!

I created two sandboxes:

To workaround the problem, I created this function which makes sure no error is bubbling up:

import { mutate } from "swr";

function safeMutate(key, action, revalidate) {
  return new Promise((resolve, reject) => {
    mutate(
      key,
      (oldValue) => {
        return action(oldValue).catch((error) => {
          reject(error);
          !revalidate && mutate(key, null); // wont work without null
        });
      },
      revalidate
    ).then(resolve);
  });
}

One drawback is that when setting revalidate to false and an error is thrown, we need to mutate to null to force revalidation (see comment "wont work without null").

As described in the docs

many POST APIs will just return the updated data directly, so we don’t need to revalidate again.

In fact, we need to revalidate at least when there is an error to make it go away.

Additional Context

SWR version 1.0.1

felixroos avatar Oct 13 '21 11:10 felixroos

Thank you for opening this! This is currently by design, but I think we can improve it so we can differentiate "fetch" errors and "mutate" errors (haven't found a good design for it yet). For the same reason, we need the data and isValidating states to be context-aware (related to #1316). One way to simplify all these is using the upcoming useSWRMutation feature (#1450).

I'll mark this issue as "discussion".

shuding avatar Nov 01 '21 12:11 shuding

I just discovered the SWR 1.1.0 also swallows null errors. https://codesandbox.io/s/cocky-smoke-kv4ir?file=/src/App.tsx

In this scenario, opts is undefined, so SWR encounters an error on !opts.skip. Enabling the ts null check flag would've likely caught it, but it's not enabled in this codebase.

When SWR encounters this error, it stays silent. the returned error stays undefined.

  const { data } = useSWR(
    () => (somethingValid && !opts.skip ? key : null),
    (key) => fetcher(api, key)
  );

Is this expected behavior?

dangdennis avatar Dec 10 '21 22:12 dangdennis

@dangdennis That might not be related to this thread, but did you mean conditional fetching (the key function throws an error, which pauses the request).

shuding avatar Dec 11 '21 02:12 shuding

Hah, actually you’re very right. I forgot that a thrown exception are treated the same as nulls.

dangdennis avatar Dec 11 '21 03:12 dangdennis