fetchPolicy: cache-only return no errors when cached item is missing
Intended outcome:
I'm using useQuery with the fetchPolicy: "cache-only" with an InMemoryCache that is primed during SSR and .restore on the client:
const { loading, data, error } = useQuery(QUERY, {
fetchPolicy: "cache-only",
errorPolicy: "all",
})
There are a lot of queries flying around that might invalidate data. When this happens, useQuery cannot refetch the query due to the cache policy being set to cache-only (which is good), and I expect an error to be set in the result. That way the error can be tracked since this is basically a coding error.
Actual outcome: Instead of an error being set in the result, there are warnings being logged to the console and the result is:
{ data: undefined, error: undefined, loading: false }
I need to now detect this special case and log a custom error myself.
Versions
System:
OS: macOS 10.15.7
Binaries:
Node: 14.15.1 - ~/.config/nodenv/versions/14.15.1/bin/node
Yarn: 1.22.10 - ~/code/release-page/node_modules/.bin/yarn
npm: 6.14.8 - ~/.config/nodenv/versions/14.15.1/bin/npm
Browsers:
Chrome: 87.0.4280.88
Firefox: 84.0
Safari: 14.0
npmPackages:
@apollo/client: ^3.2.5 => 3.3.2
apollo: ^2.31.2 => 2.31.2
apollo-link-persisted-queries: ^0.2.2 => 0.2.2
I have a similar problem. Until this is fixed, does anyone have any tips on figuring out why the data in the cache is invalid?
@jlek This is probably too late to help you but here's my tip...
Whenever this happens to me, it's always because a query that doesn't request a field populates the cache and a later query asks for another field and it's missing. The apollo client very unhelpfully drops the error on the ground even though it knows what field is missing. The gross way to figure it out is to put a breakpoint in @apollo/client/core/ObservableQuery.js around line 85 (search for diff = this.queryInfo.getDiff). You will see the return of void 0 - meaning no data for you. The diff, though, knows which fields are missing and could spit them out as console.warn - it just doesn't. Open up the diff in the watch window and you're set.
OR... less gross... set "returnPartialData" on your query options. Dump the output to console and compare what comes back with what you queried for. The missing fields will be the ones that are the problem. Another query will have hit the same object without asking for some of the fields.
@romeovs I don't think it's just cache only. I think it happens anytime you don't specify network-only.
@benjamn We need your clarification here very much. What is the intended behavior when fetchPolicy=cache-only and returnPartialData=false (or when no returnPartialData is passed to watchQuery at all)? What should've been returned if there is no complete data in the cache yet?
Because currently, it looks like watchQuery ALWAYS returns partial data when cache-only is used, no matter what passed in returnPartialData (or not passed at all). I.e. watchQuery is always partial for cache-only queries, which sounds a little unexpected.
P.S. There seems to be a work-around which hurts performance, to call client.readQuery() inside watchQuery().subscribe():
client
.watchQuery({ query, variables, fetchPolicy: "cache-only" })
.subscribe(({ data: dataOftenPartial }) => {
let data;
try {
data = client.readQuery({ query, variables });
} catch (e) {
// No full data in the cache, only a partial one.
}
if (!data) {
return;
}
... work with data here, it's guaranteed to be non-partial...
});
But it add a lot of extra CPU cycles: readQuery() redoes the same job as watchQuery() does, plus I guess exception message generation in e also takes time.
Bump on this, did anyone solve this issue? Running into this as well, hard to determine if an actual error.
Any updates here? Documentation says that the query should throw an error too. https://www.apollographql.com/docs/react/data/queries/#cache-only
Workaround
Set the log verbosity to debug
// main.ts
import {
ApolloClient,
InMemoryCache,
setLogVerbosity,
HttpLink,
} from "@apollo/client";
const apolloClient = new ApolloClient({
link: HttpLink,
cache: new InMemoryCache(),
});
+ setLogVerbosity("debug");
And enable showing of debug messages in the console

Explanation
According to the documentation, an error should be thrown, but this was changed in https://github.com/apollographql/apollo-client/pull/8604, to only print a debug message. The documentation is outdated after that pull request.
@benjamn Should the following line actually be a console.log or console.warn call instead of a console.debug call?
https://github.com/apollographql/apollo-client/blob/e079cc1ad31dae9831dbd13a6e7636384e48e9e9/src/core/ObservableQuery.ts#L982
Changing this to be a console.log call would surface missing cache errors without having to increase the verbosity. Returning invalid values ~almost always~ sometimes causes Cannot read properties of undefined errors and should be "exceptional".
If you do not want to surface these type of errors for all users in a new update, I could create a pull request to update the docs on how to show these errors. Should i do that?
Ugh we've been fighting with silently failing queries for months, only to finally stumble on this very old issue. This is really frustrating and there's no indication by default why queries are failing when using cache-only. Any time we go to add a new field, this starts happening because any existing cache is missing the field....
@benjamn please do something about this, it's one of the roughest edges I've run into since starting with Apollo Client 2 years ago. The fact that it's been open so long is wild.
At a minimum we need to be able to detect and log this situation in the wild when adding properties causes stale cache to become un-queryable using cache-only policy. The ideal solution would be to remind devs to define a read function that can return a default value missing fields—silently failing (without even an error from the query) is ridiculous.