48
votes

I am using Apollo Client to make an application to query my server using Graphql. I have a python server on which I execute my graphql queries which fetches data from the database and then returns it back to the client.

I have created a custom NetworkInterface for the client that helps me to make make customized server request (by default ApolloClient makes a POST call to the URL we specify). The network interface only has to have a query() method wherein we return the promise for the result of form Promise<ExecutionResult>.

I am able to make the server call and fetch the requested data but still getting the following error.

Error: Network error: Error writing result to store for query 
{
   query something{
      row{
         data
      }
   }
}
Cannot read property 'row' of undefined
    at new ApolloError (ApolloError.js:32)
    at ObservableQuery.currentResult (ObservableQuery.js:76)
    at GraphQL.dataForChild (react-apollo.browser.umd.js:410)
    at GraphQL.render (react-apollo.browser.umd.js:448)
    at ReactCompositeComponent.js:796
    at measureLifeCyclePerf (ReactCompositeComponent.js:75)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (ReactCompositeComponent.js:795)
    at ReactCompositeComponentWrapper._renderValidatedComponent (ReactCompositeComponent.js:822)
    at ReactCompositeComponentWrapper._updateRenderedComponent (ReactCompositeComponent.js:746)
    at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:724)
    at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:645)
    at ReactCompositeComponentWrapper.performUpdateIfNecessary (ReactCompositeComponent.js:561)
    at Object.performUpdateIfNecessary (ReactReconciler.js:157)
    at runBatchedUpdates (ReactUpdates.js:150)
    at ReactReconcileTransaction.perform (Transaction.js:140)
    at ReactUpdatesFlushTransaction.perform (Transaction.js:140)
    at ReactUpdatesFlushTransaction.perform (ReactUpdates.js:89)
    at Object.flushBatchedUpdates (ReactUpdates.js:172)
    at ReactDefaultBatchingStrategyTransaction.closeAll (Transaction.js:206)
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:153)
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:62)
    at Object.enqueueUpdate (ReactUpdates.js:200)

I want to know the possible cause of the error and solution if possible.

4
what is { query something{ row{ data } } } supposed to be?Jaromanda X
It is the graphql query that specifies the data required by the componentreturn007
whenever you use "fetchPolicy={"cache-and-network"}", you must include "id" for each graphql object. { query something { id row { " id" data } } }MechaCode

4 Answers

69
votes

I had a similar error. I worked it out by adding id to query. for example, my current query was

query  {
  service:me {
    productServices {
      id
      title
    }
  }
}

my new query was

query  {
  service:me {
    id // <-------
    productServices {
      id
      title
    }
  }
}
31
votes

we need to include id, otherwise it will cause the mentioned error.

{
   query something {
      id
      row {
         id
         data
      }
   }
}
27
votes

I've finally found out what is causing this issue after battling with it in various parts of our app for months. What helped to shed some light on it was switching from apollo-cache-inmemory to apollo-cache-hermes.

I experimented with Hermes hoping to mitigate this ussue, but unfortunately it fails to update the cache the same as apollo-cache-inmemory. What is curious though is that hermes shows a very nice user friendly message, unlike apollo-cache-inmemory. This lead me to a revelation that cache really hits this problem when it's trying to store an object type that is already in the cache with an ID, but the new object type is lacking it. So apollo-cache-inmemory should work fine if you are meticulously consistent when querying your fields. If you omit id field everywhere for a certain object type it will happily work. If you use id field everywhere it will work correctly. Once you mix queries with and without id that's when cache blows up with this horrible error message.

This is not a bug-it's working as intended, it's even documented here: https://www.apollographql.com/docs/react/caching/cache-configuration/#default-identifiers

2020 update: Apollo has since removed this "feature" from the cache, so this error should not be thrown anymore in apollo-client 3 and newer.

3
votes

I had a similar looking issue.

Perhaps your app was attempting to write (the network response data) to the store with the wrong store address?

Solution for my problem

I was updating the store after adding a player to a team:

// Apollo option object for `mutation AddPlayer`
update: (store, response) => {
  const addr = { query: gql(QUERY_TEAM), variables: { _id } };
  const data = store.readQuery(addr);
  stored.teams.players.push(response.data.player));
  store.writeQuery({...addr, data});
}

I started to get a similar error above (I'm on Apollo 2.0.2)

After digging into the store, I realised my QUERY_TEAM request made with one variable meta defaulting to null. The store "address" seems to use the *stringified addr to identify the record. So I changed my above code to mimic include the null:

// Apollo option object for `mutation AddPlayer`
update: (store, response) => {
  const addr = { query: gql(QUERY_TEAM), variables: { _id, meta: null } };
  const data = store.readQuery(addr);
  data.teams.players.push(response.data.player));
  store.writeQuery({...addr, data});
}

And this fixed my issue.

* Defaulting to undefined instead of null will probably avoid this nasty bug (unverified)

Further info

My issue may be only tangentially related, so if that doesn't help I have two peices of advice:

First, add these 3 lines to node_modules/apollo-cache-inmemory/lib/writeToStore.js to alert you when the "record" is empty. And then investigate _a to understand what is going wrong.

exports.writeResultToStore = writeResultToStore;
function writeSelectionSetToStore(_a) {

    var result = _a.result, dataId = _a.dataId, selectionSet = _a.selectionSet, context = _a.context;
    var variables = context.variables, store = context.store, fragmentMap = context.fragmentMap;

    +if (typeof result === 'undefined') {
    +    debugger;
    +}

Second, ensure all queries, mutations and manual store updates are saving with the variables you expect