apollo-client: readQuery crashes if there is nothing in the store

Intended outcome:

I want to check whether or not the apollo cache(store) has a watchQuery registered for a query name (ex: get_comments). I want to use readQuery (or a similar method?) to check the store and if there is nothing, I will get an undefined or null, or -1 etc. Something to indicate that there s no watchQuery exists under that query name.

Actual outcome:

When I try to read something from cache via readQuery, the app crashes if the query doesn’t match. The error I get is below:

ERROR Error: Uncaught (in promise): Error: Can't find field collections on object (ROOT_QUERY) undefined.

I can’t catch this error, since the return of the readQuery is not a promise or observable bur just a simple object. This error continues even if I convert the return to Observable via Observable.of(…readQuery())

How to reproduce the issue:

Just try to readQuery a random query name (ex: xwyz_xxx) and you should be able to get the error (which I couldn’t managed to catch before it crashes the app)

Please let me know if I am missing something completely. I am not very experienced in this repo. Thanks for the help.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 13
  • Comments: 24 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Would it be alright if readQuery returned null with the helpful error message? Am i the only one not a fan of try/catching all my readQuerys?

@helfer the design of this to be an error state seems suspect. Particularly since there is no guarantee that the cached data would exist for a related query at the time say a mutation attempts to update records related to it which may only load on certain pages of a website. A site of any complexity is going to regularly run into this all the time because there is no predictability that any related queries have been cached yet.

Unwinding stacks or silencing errors (which may unintendedly silence more than the target error) is expensive and issue-prone. This problem could be solved without creating a breaking change by either adding a new method such as hasQuery() or by adding in an option on DataProxyReadQueryOptions like throwErrorOnNotFound=false to retain existing behavior but provide the option to avoid try/catch & wasteful stack unwinding or internal error handling logic for this condition.

Hey guys, any update on this? I really dislike writing all these try / catch 😦

I’m with @rpedroni and @matthewerwin. It would be super nice to have to use a try/catch and that hasQuery() function would be amazing.

now 2.1 version still need use try/catch ?

I think this issue should be open again

We should be able to have another options apart form variables and query, something like : skipError (boolean)

This is still an issue for sure. It looks like one of the apollo team migrated an existing issue for it to their new suggestions issue tracker - https://github.com/apollographql/apollo-feature-requests/issues/1 Maybe it will get more traction there.

+1 I have the same problem. I’ve a list of item (which launch the main query) with an add button . The add button drive to a form where it’s possible to add an item (mutation with query update). If the user follow this path it works such as the main query was previously queried and is present in the cache. But, if the User goes directly to the Add form without passing to the list of items it crashes as the store in empty. Such story path is very basic and common.

Of course, i can add this try/catch around the update function. But it’s very verbose and easy to forget. It would be much cleaner to have one of the following features:

  1. As @helfer said, a simple NULL return if the cache is empty for a given query. if it break the main Apollo coding rules (such as it’s not a promise as mentioned by @helfer), then:
  2. a function to check if a query exist in the cache or not as @matthewerwin suggested
  3. Or, a “tryUpdate/skipError” boolean parameters to control how should react the update in case of error.

you can write typePolicy and return null when data is not in store, like this:


 new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          fieldName: {
            read: fieldName => {
              return fieldName || null;
            },
          },
        },
      },
    },
  });

What’s the status on this ? try/catch isn’t elegant in most cases. and is quite expensive

@helfer, @cesarsolorzano

readQuery throws an error whenever the cache/store is empty as mentioned here.

However, I have a use case where I need to conditionally check if the cache exists in the store, if it exists, update it via writeQuery, if not, ignore it.

because readQuery throws an error when the query fails, I need to wrap it in a try/catch block to silent it.

Is this the right way? Or is there another way to conditionally check if the cache exists in the store?

Here’s a snippet of what I’m currently doing:

graphql(DELETE_PARENT_MUTATION, {
  props: ({ mutate, ownProps: { topic } }) => ({
    deleteParent: variables =>
      mutate({
        variables: { ...variables },
        update: (proxy, { data }) => {
          const deletedTopicId = data.deleteTopicById.topic.id;
          const parentTopicId = topic.parentTopic.id;

          try {
            const prev = proxy.readQuery({
              query: TOPICSPAGE_QUERY,
              variables: { topicId: parentTopicId }
            });
            proxy.writeQuery({
              query: TOPICSPAGE_QUERY,
              data: update(prev, {
                topic: {
                  childrenTopics: {
                    edges: {
                      $apply: edges => edges.filter(({ node }) => node.id !== deletedTopicId)
                    }
                  }
                }
              })
            });
          } catch (e) {} // eslint-disable-line
        }
      })
  })
})

It’s apollo-cache-inmemory/lib/readFromStore.js -> diffQueryAgainstStore() that throws errors if there are missing fields. I think that there are two categories of missing fields.

  1. Missing fields that are a result of mismatched fragments that access the same cache data, i.e. trying to grab fields that were never pulled with the original network access [definitely deserves a thrown error, as this is probably a programmer error], and
  2. The cache signature is missing from the store entirely, i.e. it has not been initialized [this should return null, not throw an error].

It seems to me that everyone would be relatively mollified if diffQueryAgainstStore() did not throw an error for the case where the query doesn’t exist in the cache yet.

Performance of try/catch in js is still expensive https://jsperf.com/try-catch-performance-jls/2 Specifically, when the error condition is being hit. Can you please try adding in either an option to skip the error and return, or alternatively return undefined instead?