apollo-client: Fetch policy no-cache returns null data

Intended outcome:

Run a query and receive non-null data when using fetchPolicy: 'no-cache'. Tested on Node and in Browser.

client.query({query, fetchPolicy: 'no-cache'})

Actual outcome:

The data property is null:

{
  data: null
  loading: false
  networkStatus: 7
  stale: true
}

How to reproduce the issue:

Node.js

  1. Visit this runkit and fork it: https://runkit.com/razorx/apollo-client-no-cache/4.0.1
  2. Run the first box to initialize.
  3. Run the second box to run a query with the default fetch policy: the Promise will eventually resolve with good data (data: {...} ). (expected)
  4. Run the second box to run a query with the no-cache fetch policy: the Promise will eventually resolve with no data (data: null). (unexpected)
  5. Run the second box to run a query with the network-only fetch policy: the Promise will eventually resolve with good data. (expected)

Browser

  1. Visit https://codesandbox.io/s/znx9n9x943
  2. Run the code with the “refresh” button in the right pane.
    • clientA works with default fetch policy: returns non-null data. (expected)
    • clientB does not work with no-cache fetch policy: returns null data. (unexpected)
    • clientC works with default fetch policy (returns non-null data), then the query is repeated again with clientC, this time with no-cache fetch policy, and the data returns non-null! (what?)

Version

  • apollo-client@2.2.3

Contents of the runkit for reference

require('isomorphic-fetch')
require('graphql')
const { ApolloClient } = require('apollo-client')
const { HttpLink } = require('apollo-link-http')
const { InMemoryCache } = require('apollo-cache-inmemory')
const gql = require('graphql-tag')

const uri = 'https://graphql-pokemon.now.sh/graphql'

const query = gql`{
  pokemon(name: "Pikachu") {
    id
    number
    name
  }
}`

const client = new ApolloClient({
  link: new HttpLink({uri}),
  cache: new InMemoryCache()
})

client.query({query})
  .then(data => console.log(data))
  .catch(error => console.error(error))
  
// => gives good data
  
 const clientNoCache = new ApolloClient({
  link: new HttpLink({uri}),
  cache: new InMemoryCache()
})

clientNoCache.query({query, fetchPolicy: 'no-cache'})
  .then(data => console.log(data))
  .catch(error => console.error(error))
  
// => gives NULL data

const clientNetworkOnly = new ApolloClient({
  link: new HttpLink({uri}),
  cache: new InMemoryCache()
})

clientNoCache.query({query, fetchPolicy: 'network-only'})
  .then(data => console.log(data))
  .catch(error => console.error(error))
  
// => gives good data

Contents of the browser example for reference

import { gql, graphql } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloProvider } from 'react-apollo';
import App from './App';

const uri = 'https://qkv3mq9rp.lp.gql.zone/graphql'

const clientA = new ApolloClient({
  link: new HttpLink({uri}),
  cache: new InMemoryCache()
});

const clientB = new ApolloClient({
  link: new HttpLink({uri}),
  cache: new InMemoryCache()
});

const clientC = new ApolloClient({
  link: new HttpLink({uri}),
  cache: new InMemoryCache()
});

const query = gql`{
  people {
    id
    name
  }
}
`

clientA.query({query})
  .then(data => document.write('A cache<br \><br \>' + JSON.stringify(data)))
  .then(() => clientB.query({query, fetchPolicy: 'no-cache'}))
  .then(data => document.write('<br \><br \>B no-cache<br \><br \>' + JSON.stringify(data)))
  .then(() => clientC.query({query}))
  .then(data => document.write('<br \><br \>C cache<br \><br \>' + JSON.stringify(data)))
  .then(() => clientC.query({query, fetchPolicy: 'no-cache'}))
  .then(data => document.write('<br \><br \>C no-cache<br \><br \>' + JSON.stringify(data)))
  .catch(error => console.error(error))

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 25
  • Comments: 34 (3 by maintainers)

Commits related to this issue

Most upvoted comments

After several trails I figured data is always null whenever there are missing fields from the projected result. For instance, if we’re supposed to query an user like: user { uuid email picture } and for some reason the server does not return field picture, then result will be:

{
  data: null
  loading: false
  networkStatus: 7
  stale: true
}

I’ve also noticed we’ll get a Missing field picture warning on the console.

In my particular case, my backend never serializes null values. Since user’s picture and many other fields are optional (nullable), we constantly face this problem.

Does anyone have an idea why those missing fields break the result causing this issue?

Have same issue on apollo-client@2.4.12, why this is closed?

Any updates on this?

I’m actually experiencing this issue from multiple sides. In some cases, the query works with “network-only” but does not work with “no-cache”, whereas, in other queries, “network-only” does not work, but “no-cache” does. I’ve tried to see whether my issue might be related to the missing fields @jdorleans mentioned, but that does not seem to be the case. Oh, and data indeed does seem to be undefined instead of null, as @sreuter mentioned. Somehow, reloading the whole page does seem to solve the issue & everything is fetched properly.

Why is this closed again? There’s not even a workaround, save an actual fix for this.

@rschef I need this to work in a system which doesn’t know about react and uses this client directly, so unfortunately that workaround won’t be an option for me.

I poked around a little in QueryManager.ts but I couldn’t find an obvious reason for this bug.

I’m hoping someone more familiar with the code will be able to prioritize and find this quickly. I would consider this a serious bug as I could rephrase the issue as apollo-client does not support the most basic GraphQL operation: running a query and returning the correct result (without the added complexity of caching).

I’m still having this issue (data is {}) on 2.4.2

@kamranayub this issue still persists randomly.

From what we could gather, for no apparent reason, once every few times (less than 10 in our case) the Query component will trigger twice when fetchPolicy is set to no-cache. The first invocation will have the data, the second invocation will not.

We have replaced all our “no-cache” policies with “network-only” and will continue monitoring.

Please re-open this issue or let me know if I need to open a new one.

We encountered this issue and resolved via insight from @jdorleans’s comment. When the response does not include a field you’re expecting the entire data object will be null.

The same problem with the Query component. It returns normal data once, then data = {} with the same query (nothing is changed just component is rerendered) when fetchPolicy is ‘no-cache’

This was fixed in release 2.3.8 by hwillson

@jdorleans You have no idea how many hours you saved me. I was going in a rabbit hole trying to find the answer. Thank you

After several trails I figured data is always null whenever there are missing fields from the projected result. For instance, if we’re supposed to query an user like: user { uuid email picture } and for some reason the server does not return field picture, then result will be:

{
  data: null
  loading: false
  networkStatus: 7
  stale: true
}

I’ve also noticed we’ll get a Missing field picture warning on the console.

In my particular case, my backend never serializes null values. Since user’s picture and many other fields are optional (nullable), we constantly face this problem.

Does anyone have an idea why those missing fields break the result causing this issue?

This insight from @jdorleans resolved the issue for me.

I still having the same issues with apollo-client@2.5.1. It only works the first query, if you request the same data always is empty, if you change some fields it works only the first request.

Still having the same issues as @bozskejkaja Neither no-cache or network-only are working for me when making @client side queries.

Confirming that this is still an issue. We’re encountering this when mocking network requests during E2E tests with Cypress.

I have the same issue as @thanpolas, also happening erratically. Running version 2.4.7 of apollo-client. If I console.log the networkStatus, I see that in the cases where it breaks it logs:

networkStatus = 1
networkStatus = 7
networkStatus = 7

instead of the expected:

networkStatus = 1
networkStatus = 7

It’s this code: https://github.com/apollographql/apollo-client/blob/6eec674f206cda11cf667a89022354b1476f5503/packages/apollo-client/src/core/QueryManager.ts#L1059-L1112

It was introduced in https://github.com/apollographql/apollo-client/pull/2934

Basically, if fetchMoreForQueryId is not present, it tries to get the result from the cache even though it was never set (right above, if (fetchPolicy !== "no-cache")).

The branch needs to be updated to use result.data if no-cache is used, I think:

if (fetchMoreForQueryId || fetchPolicy === "no-cache")

Not sure what implications that has.

I’m running into this right now because the cache actually seems to be causing performance issues in our use case and I wanted to try bypassing it; but I can’t due to this bug 😦 If I can figure out how to develop this locally, I could try updating it.

@jbaxleyiii Should I try to update the branch as I mentioned to fix this issue? Do you see any issues with that approach?