apollo-client: useMutation onCompleted executed when errors present

Intended outcome:

I have an onCompleted callback defined on the options of useMutation. I only want onCompleted to execute when no errors are present; so, I’ve set defaultOptions: { query: { errorPolicy: 'all' }, mutate: { errorPolicy: 'all' } } on the ApolloClient.

This is the expected functionality that is described on the docs image

Actual outcome:

When a GraphqlError occurs, the onCompleted function is still executed with null data.

How to reproduce the issue:

This is the gist of our setup. I’m working on reproducing the issue on a small app as well, and will post the links on here once that is up and running.

...

const client = new ApolloClient({
  link: ApolloLink.from([
    onError(({ operation, forward, response }) => {
      // Do stuff to handle errors

      forward(operation);
    }),
    new HttpLink({
      uri: `http://localhost:3000/api/graphql`,
      credentials: 'include'
    })
  ]),
  cache: new InMemoryCache(),
  defaultOptions: {
    query: { errorPolicy: 'all' },
    mutate: { errorPolicy: 'all' }
  }
});

...

const rootElement = document.getElementById('root');

ReactDOM.render(
  <React.StrictMode>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </React.StrictMode>,

  rootElement
);
...

const MyComponent = () => {
  const [mutation, { loading, error }] = useMutation(
    GQL_MUTATION,
    {
      onCompleted: (data) => {
        console.log('onCompleted executed with:');
        console.log(data);
      }
    }
  );

  return (
    <>
      <div>{JSON.stringify(error)}</div>
      <button
        disabled={loading}
        onClick={() => mutation()}
      >
        Execute Mutation
      </button>
    </>
  );
};

Versions

"@apollo/client": "^3.5.6"

System:
    OS: macOS 11.6.4
  Binaries:
    Node: 16.13.1 - ~/.nvm/versions/node/v16.13.1/bin/node
    Yarn: 1.22.17 - /usr/local/bin/yarn
    npm: 8.1.2 - ~/.nvm/versions/node/v16.13.1/bin/npm
  Browsers:
    Chrome: 99.0.4844.51
    Safari: 15.3

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 9
  • Comments: 16 (6 by maintainers)

Most upvoted comments

I just ran into this using 3.6.4.

useMutation’s onCompleted appears to be called on any successful network response regardless of errors, data, or errorPolicy. I looked back through the history and it seems this has always been the case.

https://github.com/apollographql/apollo-client/blob/67a13b5331047264797cb50e2b19bf1ae6bacd85/src/react/hooks/useMutation.ts#L104

By comparison useQuery’s has some level of protection: https://github.com/apollographql/apollo-client/blob/67a13b5331047264797cb50e2b19bf1ae6bacd85/src/react/hooks/useQuery.ts#L505-L513

The inconsistent behavior is surprising especially since the documentation doesn’t reflect reality:

A callback function that’s called when your mutation successfully completes with zero errors (or if errorPolicy is ignore and partial data is returned).

This function is passed the mutation’s result data.

Hey all 👋

Given that the documentation states that onCompleted should be called with zero errors, I would agree this should be classified as a bug. I can’t guarantee a timeline on a fix, but if any of you wants to submit a PR to fix the issue, we’d be happy to look at it!


@abd30590 from what I understand with the GraphQL spec response format, null data with no errors is an impossible state. I find this section on data to be relevant here (emphasis mine):

7.1.1 Data

The data entry in the response will be the result of the execution of the requested operation. If the operation was a query, this output will be an object of the query root operation type; if the operation was a mutation, this output will be an object of the mutation root operation type.

If an error was raised before execution begins, the data entry should not be present in the result.

If an error was raised during the execution that prevented a valid response, the data entry in the response should be null.

I’d expect the only time you’d ever see onCompleted called when your server returns errors is with errorPolicy: 'none' since that strips out all errors from the response. This aligns with our documentation.

A callback function that’s called when your mutation successfully completes with zero errors (or if errorPolicy is ignore and partial data is returned).

I’m on 3.5.10 and experienced this exact same behavior