question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Mutations ignore partial results and the cache never gets updated

See original GitHub issue

I’ve been migrating a large codebase to the newest version of apollo for a while now and keep stumbling into bugs & undocumented behavior. The latest one being a pretty serious issue for us, because it basically makes the cache useless and prevents us from trusting it that entities will be updated after a mutation.

If a mutation passes successfully and returns data, but one of the optional subfields in the returned data has thrown an error in it’s resolver, the default behavior of apollo server is to set that particular field to null and to record the error that was thrown in the errors array. That’s completely fine, because it gives us access to the “partial” data and also gives us visibility into the error that was thrown for a particular subfield (I’m using errorPolicy: 'all'). However the cache never gets updated and the entire result of the mutation is ignored, even though the mutation was actually successful and a valid entity was returned (even though an optional deeply nested subfield was null, because it threw an error during it’s resolution from let’s say a 3rd party API).

I believe the offending line is https://github.com/apollographql/apollo-client/blob/ed7c5bb67129dbb2db693f9c3dbf582804a14bb3/src/core/QueryManager.ts#L1083 This is a very naive approach of handling mutation results. It does not respect responses with partial data and field errors in them, nor any errorPolicy. There should be an additional check to see if there is any returned data, not only if errors exist, because sometimes they are just field resolution errors from a deeply nested subtype of the returned supertype.

Intended outcome:

To have mutations that pass successfully and return data be respected, regardless of whether a deeply nested subtype failed one of it’s field resolutions and returned null for it.

Actual outcome:

Mutations that pass successfully and return data are ignored if there’s an irrelevant field error.

Versions

npmPackages: @apollo/client: ^3.1.3 => 3.1.3

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:3
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
knedev42commented, Sep 17, 2020

@benjamn sorry for taking a bit longer in order to try it out, I just got swarmed with other work.

So handling partial responses seems to work fine. But now there’s a different problem. If the mutation returns an actual error, the update function gets called and the promise gets resolved. Now the promise getting resolved isn’t that big of a deal at least for us, since we’re not actually relying on it. But the update function shouldn’t really be called when the mutation failed 🤷

I skimmed through the code and I believe that’s because the check is only for whether there is data in the response. However when you throw from a mutation in apollo-server, the data property does get populated, but the keys in it (the mutations that were called) are null. So I think the check for a successful mutation should be - there’s data and any of the keys at the root of data are not null. Otherwise it’s just unusable, without guarding in every single update function (also the promise resolving is a bit odd, but it is what it is). Or if we should guard against mutation failures in our update functions, then that should probably be thoroughly documented and people should be aware of it.

Thanks again, and sorry for the small delay 😃

2reactions
knedev42commented, May 20, 2021

Just wanted to let you know that I tried the latest version again (v3.3.19) and the behavior is still the same as my last comment - mutations that fail completely (throw an error) call the update function and the promise is getting resolved.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Advanced topics on caching in Apollo Client
In certain cases, writing an update function to update the cache after a mutation can be complex, or even impossible if the mutation...
Read more >
Auto-update of apollo client cache after mutation not affecting ...
Provide an update function to your useMutation hook that tells Apollo how to update the cache based on the results of the mutation....
Read more >
Cache Updates | urql Documentation
Local Resolvers passively compute results and change how Graphcache traverses and sees its locally cached data, however, for mutations and subscriptions we ...
Read more >
Manual Cache Updates - Redux Toolkit
When you wish to perform an update to cache data immediately after a mutation is triggered, you can apply an optimistic update ....
Read more >
Query Invalidation | TanStack Query Docs
Invalidate every query in the cache ... that use normalized caches would attempt to update local queries with the new ... Get QueryClient...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found