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

Unhandled Rejection (Error): GraphQL error: Authentication required #6070

Closed
CosmaTrix opened this issue Mar 22, 2020 · 44 comments
Closed

Unhandled Rejection (Error): GraphQL error: Authentication required #6070

CosmaTrix opened this issue Mar 22, 2020 · 44 comments
Labels

Comments

@CosmaTrix
Copy link

Hi there,

I've been trying to implement authentication to a project of mine using apollo-client and apollo-server. It is really simple:

  1. on app load I fetch the user's info from a me query
  2. if the user isn't logged in, the server throws an AuthenticationError
  3. after login, I refetch the user's info from the me query, to update the client's cache
  4. on logout, I clear the cache using client.resetStore
  5. because of that, my app rerenders and tries to get the user's info from the me query again
  6. the user isn't logged in, the server throws an AuthenticationError
  7. but this time a see huge error screen in my React application

Looking at the dev tools, everything looks fine.

At page load, the user is not logged in. The me query returns null (and an AuthenticationError error)
image

After login, I get data from the me query
image

Finally, after logout, the me query returns again null (and an AuthenticationError error)
image

But this time my client app breaks with this error
image

I find this a bit weird because the cache at page load and after logout is the same (empty cache). And the server responses are identical, yet the client behaves differently.

My implementation is pretty similar to the one described in the official documentation (using cookies).

Does anybody have an idea why this happens?

@andrepcg
Copy link

I'm having this issue where in development any graphql error get thrown and this CRA dialog shows up. I'm using apollo-link-error and I can see the errors get there but they're still raised.

Any solution?

@CosmaTrix
Copy link
Author

I've upgraded to @apollo/client@3.0.0-beta.41 and the issue persists, but with a slightly different error stack.

image

@silkyland
Copy link

same here

@milban
Copy link

milban commented Apr 8, 2020

same here apollo-client^2.6.8 :(

@adildostmohamed
Copy link

adildostmohamed commented Apr 8, 2020

not sure if this helps but i had a similar issue where throwing a AuthenticationError from Apollo-Server was causing my Apollo-Client react error page to appear due to an unhandled rejection.
In my case, I wrapped my mutation in a try catch block and awaited the mutation response and it seemed to work.

IE This leads to an unhandled rejection error:

  const onSubmit = (e: React.ChangeEvent<HTMLFormElement>) => {
    e.preventDefault();
    login({ variables: { input: loginFormState } });
  };

This works and allows me to grab the error from the mutation to display on the UI

  const onSubmit = async (e: React.ChangeEvent<HTMLFormElement>) => {
    e.preventDefault();
    try {
      await login({ variables: { input: loginFormState } });
    } catch (e) {
      console.error(e);
    }
  };

@josuevalrob
Copy link

josuevalrob commented Apr 10, 2020

@adildostmohamed it works... but is not a clean solution at all.

I am implementing the HOC approach from Apollo, but so far, it doesn't works. I mean:

<Mutation mutation={requestAccess} onCompleted={handleComplete} >
        { (graphQlCallback, { loading, error }) => (
                <>
                <Form onSubmit={ e => handleInvitation(e, graphQlCallback) ...>
                {/* here the error destructured variable from the callback is filled with the error data */}
                {error && <p>Error :( {error.message}</p>}
                {error && console.error(error)} {/* you can see the error object here. */}
                </>
        )}
</Mutation>

Also in the client, I can set up the error handler, but it doesn't avoid to broken sites...

const Client = new ApolloClient({
  uri : process.env.REACT_APP_API_URL,
  cache: new InMemoryCache({addTypename: false}),
  onError: ({networkError, graphQLErrors}) => {
    graphQLErrors && console.log('⚛️ GraphQl Error ⚛️',graphQLErrors)
    networkError && console.log('👮🏻‍♀️ network error', networkError)
  }
})

The try/catch option propouse from @adildostmohamed :

const handleInvitation = async (event, graphQlCallback) => {
  event.preventDefault();
  // graphQlCallback({variables: {input:formState.values}})
  try {
    await graphQlCallback({ variables: { input: formState.values } });
  } catch (event) {
    console.error(event); //🤮
  }
};

works, but I dont think that is the best one.

Any better solution??

@adildostmohamed
Copy link

@josuevalrob if you're trying to use the onError callback I think you actually need to implement it as prop on your Mutation component itself rather than on the apolloClient instantiation alone.

ie:

<Mutation mutation={requestAccess} onCompleted={handleComplete} **onError={handleError}**>
        { (graphQlCallback, { loading, error }) => (
                <>
                <Form onSubmit={ e => handleInvitation(e, graphQlCallback) ...>
                {/* here the error destructured variable from the callback is filled with the error data */}
                {error && <p>Error :( {error.message}</p>}
                {error && console.error(error)} {/* you can see the error object here. */}
                </>
        )}
</Mutation>

You should then be able to use your handleInvitation function as you had it before:

const handleInvitation = (event, graphQlCallback) => {
  event.preventDefault();
  graphQlCallback({variables: {input:formState.values}})
};

If you do this you shouldn't need to catch the error from the call to the mutate function if you're not fan of that.

Alternatively if you don't want to use the onError prop on the Mutation component to specify the onError callback, you can use an alternative syntax to the try/catch scenario to something like:

const handleInvitation = (event, graphQlCallback) => {
  event.preventDefault();
  graphQlCallback({variables: {input:formState.values}}).catch(err => doSomethingWithError(err))
};

Hopefully one of these approaches works for your needs

@jeggy
Copy link

jeggy commented Apr 21, 2020

I have a big application that sometimes does try to catch and sometimes it is just using the generic onError functionality we have created.

Easiest fix for us was to update the apolloClient configuration with defaultOptions like this:

export default new ApolloClient({
  link,
  cache,
  defaultOptions: {
    mutate: { errorPolicy: 'ignore' },
  },
});

But the problem with this is that now the promises always resolve successfully, so the places that are using the .then on the promise are always called even when the mutation is failing.

@clemente-xyz
Copy link

clemente-xyz commented Apr 28, 2020

Hi! Having the same issue here. I'm in a CRA TypeScript project using

    "@types/apollo-upload-client": "^8.1.3",
    "@types/graphql": "^14.5.0",
    "@types/node": "^13.13.4",
    "@types/react": "^16.9.34",
    "@types/react-dom": "^16.9.7",
    "apollo-boost": "^0.4.7",
    "apollo-link": "^1.2.14",
    "apollo-link-context": "^1.0.20",
    "apollo-upload-client": "^13.0.0",
    "graphql": "^15.0.0",
    "react": "^16.13.1",
    "react-apollo": "^3.1.5",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.1.2",
    "react-scripts": "3.4.1",
    "typescript": "^3.8.3",

My Apollo client onErrorLink config is:

const onErrorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors)
    graphQLErrors.map(({ message, locations, path }) =>
      console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`)
    );

  if (networkError) console.log(`[Network error]: ${networkError}`);
});

When triggering an apollo error on a mutation that I have, my app crashes:

Screen Shot 2020-04-28 at 3 44 25 PM

Any idea of how to solve this?

@masull
Copy link

masull commented Apr 29, 2020

Same here

@salza80
Copy link

salza80 commented May 6, 2020

same issue

@duro
Copy link

duro commented May 7, 2020

I'm getting the same issue as well. I'm using apollo-boost, which ships with apollo-client 2.6.8.

I have tried errorPolicy: 'all' and errorPolicy: 'ignore' and I always get an unhandled promise exception. The only way around this is the hack of catching the error and sending it to console,

But according to docs that's not how this is supposed to work. Using 'ignore' or 'all' is supposed to make errors that are sent from the server that are not network errors resolve, and simply update the error object.

I have triple confirmed that my server is returning 200, and clearly GraphQL is classifying them at GraphQL errors, else our error would say something like Unhandled Rejection (Error): Network error

Something is off here.

Here is what my code looks like if it helps:

const LOGIN = gql`
  mutation Login($email: String!, $password: String!) {
    login(password: $password, email: $email) {
      token
    }
  }
`

export const Login = () => {
  const [submitLogin, { data, error }] = useMutation<LoginResult, LoginArgs>(
    LOGIN,
    { errorPolicy: 'all' },
  )

  const onSubmit = async (
    _values: LoginFormValues,
    _formik: FormikHelpers<LoginFormValues>,
  ) => {
    submitLogin({
      variables: {
        email: _values.email,
        password: _values.password,
      },
    })
  }

  const [submittedOnce, setSubmittedOnce] = useState(false)
  const formik = useFormik<LoginFormValues>({
    initialValues: { email: '', password: '' },
    validateOnBlur: submittedOnce,
    validateOnChange: submittedOnce,
    onSubmit,
  })

  return (
    ...
  )
}

@duro
Copy link

duro commented May 7, 2020

I have traced this down, at least in @apollo/react-hooks@3.15 which which ships with apollo-boost@0.4.7 to this block of code:

https://github.com/apollographql/react-apollo/blob/4bd40a94b18102b1eb42864d2e59d52ced0303f5/packages/hooks/src/data/MutationData.ts#L81-L89

The errorPolicy is never destructured from the options, and subsequently never passed to the underlying client mutation call.

@duro
Copy link

duro commented May 7, 2020

Just updating... I upgraded my app to @apollo/client v3.0.0-beta.44 and my particular issue was resolved.

@Sergioamjr
Copy link

Sergioamjr commented May 24, 2020

Just adding a callback on onError property worked for me.

eg.

<Mutation variables={state} onError={onError} mutation={CREATE_NEW_USER}>

@ArtGurianov
Copy link

Hey guys! I had exactly the same problem. And solution was simple:

  • just change 'client.resetStore()' to 'client.clearStore()'.
    That's it! No refetching will be performed :) Happy coding!

@Juandkpa
Copy link

Juandkpa commented Jun 9, 2020

Hi guys, I'm having the same issue, I used which @ArtGurianov suggested, but it doesn't clear the store properly.. the user remains there after logout.
I posted my code and issue in stack overflow
Could you help me?

@j33n
Copy link

j33n commented Jun 15, 2020

If you are using the useMutation hook the following works:

const [login, { loading, error }] = useMutation<
    LoginMutation,
    LoginMutationVariables
  >(LOGIN, {
    onCompleted({ login }) {
      console.log("register :>> ", login, loading, error);
    },
    onError(error) {
      console.error("error :>>", error.message);
    },
  });

@Toerktumlare
Copy link

Dealing with this for 2 hours wondering why my app constantly was crashing.

Nothing about this in the official documentation, and no response from the maintainers.

@timothyjmtan
Copy link

timothyjmtan commented Jul 20, 2020

I was also having this issue. What I did in the end was to do a catch statement when invoking of tuple function. Here is my example using TypeScript and Apollo hooks:

const [addProject, {loading: loadingAddProject, error: errorAddProject, data: dataAddProject }] = useMutation<addNewProject>(ADD_NEW_PROJECT);

function addNewProject(event: React.MouseEvent<HTMLElement>){
    addProject({ variables: projectId: projectId })
        .catch((error) => {
            console.log("Error: " + error))
        });
}

After this implementation I no longer encountered the issue that the OP has.

@ntt2k
Copy link

ntt2k commented Jul 24, 2020

I have same issue ... and look like Apollo team don't care about fixing this!

@sunhak-hout
Copy link

This temporarily helps me avoid the pain of using try, catch block.

const [login, { data, loading, error }] = useLoginMutation({ onError: () => {} });

I hope to see the solution to this problem soon. Thanks for your hard work, Apollo team!

@ozokuz
Copy link

ozokuz commented Oct 11, 2020

Any progress on this? I'm having this issue with @apollo/client 3.2.3. I have tried using @sunhak-hout 's workaround but I still get errors.

@ariel-upstream
Copy link

I have a big application that sometimes does try to catch and sometimes it is just using the generic onError functionality we have created.

Easiest fix for us was to update the apolloClient configuration with defaultOptions like this:

export default new ApolloClient({
  link,
  cache,
  defaultOptions: {
    mutate: { errorPolicy: 'ignore' },
  },
});

But the problem with this is that now the promises always resolve successfully, so the places that are using the .then on the promise are always called even when the mutation is failing.

This is a nice solution if you're using the onError globally (ApolloClient), so you can catch all the API Errors on the onError method and the default error page of apollo will not appear and you will handle it

@trevorr
Copy link

trevorr commented Nov 16, 2020

Upgrading from 3.0.2 to 3.2.5 seems to have fixed this for me (without any errorPolicy workaround). What was an unhandled rejection is now correctly returned from useQuery in error.

@johnnyoshika
Copy link

johnnyoshika commented Dec 24, 2020

Upgrading from 3.0.2 to 3.2.5 seems to have fixed this for me (without any errorPolicy workaround). What was an unhandled rejection is now correctly returned from useQuery in error.

@trevorr useQuery was never a problem. It's useMutation that causes the unhandled exception and I'm still seeing it in @apollo/client version 3.3.6. Can you check your useMutation?

@johnnyoshika
Copy link

Can someone jump in explain whether this error handling behavior is a bug or by design? The same behavior happened in Apollo Client 2 (#3876), and since this hasn't been fixed yet, is this by design? If it is by design, it should be noted that the error handling behavior is inconsistent between useQuery and useMutation.

@pavelspichonak
Copy link

Looks like there are no updates related to this issue...

@pavelspichonak
Copy link

pavelspichonak commented Feb 6, 2021

@johnnyoshika looks like it is not related to both useMutation and useQuery. Because now I use only useQuery and have the same issue. And it happens only after calling client.resetStore method.

@johnnyoshika
Copy link

@pavelspichonak that's very interesting. I wonder if I'm having this issue because I'm resetting the store as well.

@jacksonbenete
Copy link

I'm not resetting the store and I'm having this same problem on useMutation.
Both @j33n and @sunhak-hout workarounds worked for me. (Thanks!)

@ModPhoenix
Copy link

I have a big application that sometimes does try to catch and sometimes it is just using the generic onError functionality we have created.
Easiest fix for us was to update the apolloClient configuration with defaultOptions like this:

export default new ApolloClient({
  link,
  cache,
  defaultOptions: {
    mutate: { errorPolicy: 'ignore' },
  },
});

But the problem with this is that now the promises always resolve successfully, so the places that are using the .then on the promise are always called even when the mutation is failing.

This is a nice solution if you're using the onError globally (ApolloClient), so you can catch all the API Errors on the onError method and the default error page of apollo will not appear and you will handle it

Maybe it helps someone

export const apolloClient = new ApolloClient({
  uri: "http://localhost:8000/",
  cache,
  defaultOptions: {
    mutate: { errorPolicy: "all" },
  },
});

@hwillson
Copy link
Member

This should no longer be an issue in @apollo/client@latest - let us know otherwise, thanks!

@JeffBaumgardt
Copy link

JeffBaumgardt commented May 25, 2021

Can we get a little more information about the resolution here? Merely saying it's fixed doesn't actually solve the larger problem here. When we get unhandled errors we turn to issues such as this to find out why and what we can do to potentially fix the issue.

Not everyone can be on the bleeding edge of the client. Also @latest also doesn't help future people coming in as latest can be different from when it was published.

Is there a PR that we can reference that addresses this issue? Is there any background that we can use for us who can't yet update our package version on a whim?

@asaadawey
Copy link

i still face the same problem
running
"@apollo/client": "^3.3.16",

const errorLink = onError(
  ({ graphQLErrors, networkError, forward, operation }) => {
    if (graphQLErrors)
      graphQLErrors.forEach(({ message, locations, path }) =>
        console.log(
          `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
        )
      );

    if (networkError) console.log(`[Network error]: ${networkError}`);
  }
);
export const client = new ApolloClient({
  link: from([authLink, loadingLink, httpLink, errorLink]),
  cache,
  defaultOptions: {
    mutate: { errorPolicy: "ignore" },
    query: { errorPolicy: "ignore" },
  },
});

@MrEmanuel
Copy link

I'm using
"@apollo/client": "^3.3.11",
"@graphql-codegen/cli": "^1.20.1",
"@graphql-codegen/typescript": "^1.21.0",
"@graphql-codegen/typescript-operations": "^1.17.14",
"@graphql-codegen/typescript-react-apollo": "^2.2.1"

graphql-codegen generates hooks for me like this one:

export function useCreateSelectionMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<CreateSelectionMutation, CreateSelectionMutationVariables>) {
        return ApolloReactHooks.useMutation<CreateSelectionMutation, CreateSelectionMutationVariables>(CreateSelectionDocument, baseOptions);
      }

When I use the hooks, I usually wrap them in a try catch-block, but for some reason this didn't work for my latest added hook.

I fixed the issue and caught the unhandled error in my react app using the onError option documented here: https://www.apollographql.com/docs/react/api/react/hooks/#options-2
Like so:

  const [updateSelection] = useUpdateSelectionMutation({
    onError: (e) => console.error('Error updating selection', e),
  })

Hope it helps someone. It's also a much better approach than try catch-blocks I think.

@GhassenRjab
Copy link

I am using @apollo/client@3.3.20, I can confirm I still have the issue.

Otherwise, when I build my app and use it, the error is handled well and I don't have the "Unhandled Rejection" screen.

The issue seems to be happening only when React is on development mode.

@supel2bloggest
Copy link

supel2bloggest commented Jul 26, 2021

I have a big application that sometimes does try to catch and sometimes it is just using the generic onError functionality we have created.

Easiest fix for us was to update the apolloClient configuration with defaultOptions like this:

export default new ApolloClient({
  link,
  cache,
  defaultOptions: {
    mutate: { errorPolicy: 'ignore' },
  },
});

But the problem with this is that now the promises always resolve successfully, so the places that are using the .then on the promise are always called even when the mutation is failing.

this work for me thanks a lot!
but I set it to

export default new ApolloClient({
  link,
  cache,
  defaultOptions: {
    mutate: { errorPolicy: 'all' },
  },
});

@aminsaedi
Copy link

same issue. setting errorPolicy to all not works!

@jerelmiller
Copy link
Member

Hey all 👋! Thanks for your patience.

I see you're using client.resetStore() here to clear out your cache, which fetches any active queries. I'm curious, does client.clearStore() serve your needs here? This works identical to resetStore, but does not fetch active queries. It makes sense your server would reject queries after logging out, but curious if those fetches need to happen in the first place.

If clearStore doesn't work here, I'd love to understand the reasons behind wanting to fetch after logout. Even more helpful would be a minimal reproduction. It's not clear to me if the me query is coming from the same component in both instances or not.

Any more information here would be helpful. Thanks!

@jerelmiller jerelmiller added the 🏓 awaiting-contributor-response requires input from a contributor label Feb 24, 2023
@github-actions
Copy link
Contributor

We're closing this issue now but feel free to ping the maintainers or open a new issue if you still need support. Thank you!

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Mar 26, 2023
@lfrallon
Copy link

Upgrading from 3.0.2 to 3.2.5 seems to have fixed this for me (without any errorPolicy workaround). What was an unhandled rejection is now correctly returned from useQuery in error.

@trevorr useQuery was never a problem. It's useMutation that causes the unhandled exception and I'm still seeing it in @apollo/client version 3.3.6. Can you check your useMutation?

Currently using the latest version of @apollo/client@3.7.12 and this issue still exists in useQuery. Not sure about the useMutation though.

Having an ErrorLink Handler like this 6070# also doesn't work.

Also, I'm not quite sure why would my useQueries still execute even though it is already unmounted. Perhaps that is the first reason why unhandled rejection occurs.

@phryneas
Copy link
Member

@lfrallon Reading through this thread, I fear that these are a lot of very different problems that just piled up in this issue - some people report it is fixed, others don't.
I fear at this point it might get confusing to have a deeper in-depth discussion in this issue.

Could you please open a new issue for your case, and please include a reproduction? The issue template should point you to a few "reproduction starters", so you don't have to create one from scratch.

@github-actions
Copy link
Contributor

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
For general questions, we recommend using StackOverflow or our discord server.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests