Apollo-client: 'ObservableQuery with this id doesn't exist: id' on unmounted component

Created on 8 Nov 2018  Â·  33Comments  Â·  Source: apollographql/apollo-client

Actual outcome:

Hello,

when any of my react native componets start fetching data and is unmounted befor finish, app yell
: Possible Unhandled Promise Rejection (id: 0): Error: ObservableQuery with this id doesn't exist: 11

There is any posibility how to prevent/catch/fix it? Its only bad setting or bug?

thanks

Versions

npx: installed 1 in 1.561s

  System:
    OS: Linux 4.15 Ubuntu 18.04.1 LTS (Bionic Beaver)
  Binaries:
    Node: 10.10.0 - /usr/local/bin/node
    Yarn: 1.10.1 - ~/.yarn/bin/yarn
    npm: 6.4.1 - /usr/local/bin/npm
  Browsers:
    Chrome: 69.0.3497.100
    Firefox: 63.0
  npmPackages:
    apollo-cache-inmemory: 1.3.6 => 1.3.6 
    apollo-cache-persist: ^0.1.1 => 0.1.1 
    apollo-client: ^2.4.5 => 2.4.5 
    apollo-link: ^1.2.3 => 1.2.3 
    apollo-link-context: ^1.0.9 => 1.0.9 
    apollo-link-error: ^1.1.1 => 1.1.1 
    apollo-link-http: ^1.5.5 => 1.5.5 
    apollo-link-logger: ^1.2.3 => 1.2.3 
    react-apollo: ^2.2.2 => 2.2.4 

Most helpful comment

Found solution.

The error is raised by Promise returned by the fetchMore call. So, you have to catch that.

Insted of just calling (as in all examples):

fetchMore({variables: {...}, updateQuery: ()=>{...}})

Instead do (in ES6 syntax):

try { await fetchMore({variables: {...}, updateQuery: ()=>{...}}) catch { }

Then the async error thrown after component unmount is catched. The updateQuery function is not called as error is thrown before that. You could also handle the error a bit better, if more finer error control is needed than just supressing all errors.

All 33 comments

+1
This happens with the graphql HOC for us. Not saying the <Query/> component doesn't do it, we use the graphql HOC 95% of the time.

Getting this in our production environment but not our staging or local, no idea how to fix.

Update: Issue was caused by an error in a related component, the error boundary caused the Query component to become unmounted.

I was seeing this, and it ended up being that I was resetting limit variables on a paginated query that uses fetchMore. I was doing it on a child component componentDidUnmount however (so it would be reset when you go back to the screen with the list). This was causing the query to refetch and immediately disappear. Not sure if that's helpful for your issue or not, but figured I'd share!

I am also getting ObservableQuery with this id doesn't exist: 13 during SSR and I cannot figure out what the problem is. In my cases it happens when I use the HOC and try to subscribeToMore AND use the updateQuery option. It works fine in the browser but on the server I get this error. If I remove the updateQuery it works fine on the server. Any ideas what to look at?

As @sghall i'm getting this also using SSR with updateQuery, randomly

Getting this in our production environment but not our staging or local, no idea how to fix.

Update: Issue was caused by an error in a related component, the error boundary caused the Query component to become unmounted.

@rlancer can you elaborate on your solution a little? Trying to diagnose a Sentry error.

@redreceipt we have a infinite scroll for our main feed with a side bar that also has an infinite scroll, we were only using Apollo to power our main feed, the sidebar ended up crashing and the only error we saw was 'ObservableQuery with this id doesn't exist: id' on unmounted component, it turned out the sidebar was within the same parent error boundary as the main feed which so when it crashed it caused our main feed to unmount hence causing the error.

I am also seeing this message. I guess it's because the query response comes back from my server, but the Query HOC has already unmounted, consequently, Apollo Client doesn't know which query to update.

That just means your query is causing the HOC to be removed from the
Virtual DOM.

On Mon, Apr 15, 2019, 8:41 AM flyer1 notifications@github.com wrote:

I am also seeing this message. I guess it's because the query response
comes back from my server, but the Query HOC has already unmounted.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/apollographql/apollo-client/issues/4114#issuecomment-483235347,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABRuf9emEz4jrX-uRfgJEp6ttHXkBv-0ks5vhHORgaJpZM4YUqnm
.

This error happens to me in the following situation. (always reproducible)

  1. In a page A which uses a query Q, click a button to fetchMore. This page has a search param in URL to get query result with different variables.
  2. Before fetchMore finishes, move to another page A' which uses the same query Q but with different search params.
  3. error ObservableQuery with this id doesn't exist happens.

I found a solution for this case; setting different keyfor <Query /> component (using search param) removes the error. If I understood correctly, it makes react to render a new <Query /> component, so it won't try to update the previous query.

I'm not sure but also suspecting that this not only happens for fetchMore, but may happen between two components with the same query in some conditions. Unfortunately, I haven't reproduced and found a solution for this "general" case.

Hope this helps.

We have the same issue. It would be great for Query to track if the underlying component is unmounted.

I am seeing this issue using the aws-appsync client that uses apollo-client 2.4.6. The original report here uses 2.4.5. Can someone confirm this is still an issue with the latest version of apollo-client (currently 2.5.1)?

Hitting this issue when the variables of my <Query> changes while a fetchMore is still in progress.

Still hapens for me in 2.6.0.

Yeah this happens for me in 2.5 when I unmount/remount my HOC. It kind of makes sense but I am lost as to how to fix it.

Normal Behaviour

  1. HOC (graphql wrapped component) is mounted, with variables offset, limit, orderBy and filter passed from props.
- User can interact with the HOC changing any of these variables using internal **state** and `fetchMore` side effects on each state variable. Every query completes.

- Even when props are changed and the initial HOC query fires again - the fetchMore is still in sync with this query id.
  • Component mounts for the first time , Network Status: 1 (loading)
  • Query completes, and data is populated into the UI, Network Status: 7 (ready)
    ... waits for user interaction
  • User clicks a header to sort the data, fetchMore is called, Network Status: 3 (fetchMore)
  • Query completes, Network Status: 7 (ready)

Abnormal Behaviour

  1. HOC (graphql wrapped component) is mounted, with variables offset, limit, orderBy and filter passed from props.
  2. User causes HOC to be unmounted, and remounted.
  • Component mounts for the first time , Network Status: 1 (loading)
  • fetchMore is called before the component is (ready), Network Status: *3(fetchMore)*
  • Query errors with 'ObservableQuery with this id doesn't exist: id', Network Status: 8 (error)

This screenshot, shows normal behaviour on the top half and abnormal behaviour after the second mount.
Screenshot 2019-05-27 at 14 23 33

What is happening

It looks like the fetchMore query is referring wrong ObservableQuery id upon remount. I'm guessing when a graphql component is unmounted the ObservableQuery is destroyed.

However it seems that the fetchMore is still referring to this destroyed query.

Workaround for my case

  • I could extract all my state into the parent component, remove all fetchMore queries and simply refire the HOC query when any props change. Although I really don't like this approach, as the logic should not be extracted to the parent component.

Question

Is it possible to fully "cleanup" a graphql component when it is unmounted? ie. the fetchMore's should only refer to the most recent query, not a previous destroyed query.

I'm having an issue which I think may be related to this. When a query is loading and the component unmounts before the query completes, then the network request gets cancelled (normal behavior). But when a fetchMore is loading and the component unmounts before it completes, then the network request does not get cancelled (abnormal behavior).

Having faced the same issue with fetchMore. Still thinking how to fix it.. the underlaying component (data search screen) can be unmounted by user by selecting or cancelling search value while fetchMore is still fetching data, be that automatic fetchMore or infinite scroll, the problem arises from the fact that the backend responses are a bit slow.

Workaround would be to disallow/delay unmount until fetchMore completes or maybe somehow catch and handle these specific errors outside from raising problem.

Found solution.

The error is raised by Promise returned by the fetchMore call. So, you have to catch that.

Insted of just calling (as in all examples):

fetchMore({variables: {...}, updateQuery: ()=>{...}})

Instead do (in ES6 syntax):

try { await fetchMore({variables: {...}, updateQuery: ()=>{...}}) catch { }

Then the async error thrown after component unmount is catched. The updateQuery function is not called as error is thrown before that. You could also handle the error a bit better, if more finer error control is needed than just supressing all errors.

@jounii That works for me, thank you! I wish there was a way to cancel the fetchMore request though.

@spilist thanks! adding a unique key to my query component (or in my case to my query hook, since i'm using react-apollo-hooks) fixed the issue

@sghall @Ethaan Did you guys manage to resolve this issue? I'm getting the exact same issue as you (randomly works), with the error jumping between Invariant Violation: ObservableQuery with this id doesn't exist: 7 and Uncaught Invariant Violation: ObservableQuery with this id doesn't exist: 51.

I'm using the following packages:

apollo-client: 2.6.3
react-apollo: 2.5.8
next: 9.0.0
react: 16.8.6

Getting the same error

👀

In my case I had a list of components sharing a connected query and found that this line was causing the problem https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/ObservableQuery.ts#L601

if you keep at least one component always subscribed to the query you shouldnt get that error

@amille14 Do you have a snippet of how you added a key to the react hook?

Second: Also curious to know how you add key to a react hook?

For those curious: Wrapping hook in HOC, and then passing a key prop solved the issue for me.

const Fetcher = ({children}) => {
  const result = myHook();
  return children(result);
}

And then render like so

<Fetcher key={someUniqueKey}>
  { results => <SomeComponent results={results} /> }
</Fetcher>

@jmurret @digitalmaster I simply passed a key in to the useQuery hook like this:

const { data, loading, error } = useQuery(myQuery, { variables: { ... }, key: 'some key' })

You can also use a key prop on apollo's Query/Mutation components like so:

<Query query={myQuery} key='some key' variables={{ ... }}>
  ...
</Query>

Note that for the hooks I was using the react-apollo-hooks package. This was before Apollo released official support for hooks. I have no idea if passing a key to Apollo's hooks will work the same way, though I do know that their hooks are based on that package so it might work.

@amille14 Thanks a ton for sharing that context. Looks like they do differ. Doesn't look like 'key' is part of Apollo React Hook:

TypeScript Error:

'key' does not exist in type 'QueryHookOptions<Data, Record<string, any>>'

Although this would be a nice feature.

Hi,

We are seeing the issue when running tests in Jest because (I think) Jest fails when exceptions are thrown in promises but not caught. For us, it happens with the graphql() HOC when the fetchMore() has been invoked but its result arrives after the component has unmounted.

For now, we have applied the following patch (to apollo-client v2.4.6) as a workaround, simply to stop Jest seeing the uncaught exception:

diff --git a/node_modules/apollo-client/bundle.umd.js b/node_modules/apollo-client/bundle.umd.js
index 63a5534..71b64e7 100644
--- a/node_modules/apollo-client/bundle.umd.js
+++ b/node_modules/apollo-client/bundle.umd.js
@@ -287,7 +287,7 @@
                     });
                 });
                 return fetchMoreResult;
-            });
+            }).catch(() => {});
         };
         ObservableQuery.prototype.subscribeToMore = function (options) {
             var _this = this;

Note, we are on apollo-client v2.4.6 because we are using aws-appsync which requires this version!

I just add key props with my Query Component

This is working!

my cord ->

query={GET_NEARBY_RIDE}
skip={isDriving}
key="999"
>
{({ subscribeToMore, data: getNearbyRide }) => {
const rideSubscriptionOptions: SubscribeToMoreOptions = {
document: SUBSCRIBE_NEARBY_RIDES,
updateQuery: this.handleSubscriptionUpdate
};
subscribeToMore(rideSubscriptionOptions);
return (...~~~)

Migrating from react-apollo-hooks to the official Apollo package squared this for me (ht @amille14 )

I am also facing this issue, any solution alternative to catching the error,
also not sure how to use the unique key, since on mount and unmount my same query is gonna call withs the same key name?

Was this page helpful?
0 / 5 - 0 ratings