-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updating with missing data makes query fail silently #2920
Comments
I am also running into this and it is very hard to debug. I'm on the web so I do get an error but it's very cryptic and not really actionable without extensive digging.
I feel it would indeed be much more useful if the cache returned null values for fields that are not yet present instead of blowing up. It would at least be easier to track down. Or if not can we at least have a reference to the query and the object missing in the error message? Something like
This way at least there's a way to know what data exactly is missing (has not previously been requested - ie the child field). In my case this happens when I deploy the app to the server where it loads legacy data. Everything works well on the client side. So even more complicated to track down. Thanks |
We're also running into this issue, and like @MrLoh and @maierson, it's also been very difficult to debug. In our particular scenario, we have one feature (feature A) making a GQL query, like this: query workspace($workspaceId: String!) {
workspace(id: $workspaceId) {
id
contract {
id
versions {
id
type
status
}
}
}
} When a new workspace is created on our platform, a contract also gets created and is associated with the workspace; however, the contract starts off with no versions. When the above query is executed against our GQL server for a newly created workspace, we get a result that looks like this: {
"data": {
"workspace": {
"id": "00000000-0000-AAAA-0000-00000000000A",
"contract": {
"id": "00000000-0000-BBBB-0000-00000000000B",
"versions": [],
"__typename": "ContractType"
},
"__typename": "WorkspaceType"
}
}
} So far, so good. Elsewhere in the app, we have another feature (feature B) that makes a different GQL query that may include contract information: query chat($workspaceId: String!, $eventId: ID!) {
workspace(id: $workspaceId) {
id
chatroom {
id
event(id: $eventId) {
id
resource {
... on ContractType {
id
versions {
id
type
}
}
}
}
}
}
}
} Above, the query is fetching a chat event that has an associated resource. A resource can take on many different types, one of which is a contract type (union shown above for brevity). You'll notice that in the first GQL query, it requests a contract's versions having fields Alright, so here's how things play out -- brace for impact... Eventually a new contract version is created, this will cause the system to send out a chat event to all users that are part of a workspace which the contract belongs to. The frontend web app that makes use of the apollo client will receive a message (via a websocket) notifying the app of a new chat event. Feature B in the web app will pick up on this notification and in turn make a call via the apollo client to get more chat event information. Once the graphql server passes back a response, the apollo client triggers all of the GQL queries associated with the workspace and contract, which in this scenario is feature A and B. In the case of feature B everything works. Nothing blows up. However, feature A does blow up, and when we look for errors we see nothing. Like @MrLoh, the issues came down to the data passed back from the server and how apollo client reconciles it. Initially a contract's public getCurrentQueryResult<T>(observableQuery: ObservableQuery<T>) {
const { variables, query } = observableQuery.options;
const lastResult = observableQuery.getLastResult();
const { newData } = this.getQuery(observableQuery.queryId);
if (newData) {
return maybeDeepFreeze({ data: newData.result, partial: false });
} else {
try {
// the query is brand new, so we read from the store to see if anything is there
const data = this.dataStore.getCache().read({
query,
variables,
previousResult: lastResult ? lastResult.data : undefined,
optimistic: true,
});
return maybeDeepFreeze({ data, partial: false });
} catch (e) {
return maybeDeepFreeze({ data: {}, partial: true });
}
}
} When digging in and examining the error, the error does include detailed information why the cache's So, going back to our scenario, for feature A, its query wants a contract version's This took us a while to track down the root cause and really understand what was going wrong. Given what we now know, I'd like to add on to @MrLoh and @maierson thoughts for what the intended outcome should be. At minimum, there should be a way to configure apollo client so that instead of silently swallowing thrown read query errors, the client will instead loudly raises the error for dev's to easily track down. Better yet, it would be really nice if there were a way to handle these type of read errors gracefully. For instance, the apollo client could provide some kind of hook to optionally handle read errors. When handling the error, queries that failed could be run again to fetch data each query expects. Anyway, apologies for such a long comment. I figured it would be useful for anyone else who is going down this long, winding road. And thanks to @MrLoh for initially raising this issue 😊 Other details
|
Ha ! It seems like I'm not the only one facing this missing data problem ! It's been 3 days since I tried to debug the following problem (only on iOS). And it is still not debugged... I figured out that the problem comes from a specific screen but I don't exactly know what makes this specific data return In your case, It seems that comes from a missing field but how did you find it ? Considering the following snippet : render() {
if (this.props.queryUserLoggedInfos.networkStatus === 1) return null;
const { userLogged } = this.props.queryUserLoggedInfos;
console.log("=========render userLogged==========");
console.log(userLogged);
console.log("====================================");
(...) I got the following result on iOS : [apollo-cache-persist] Restored cache of size 90659
=========render userLogged==========
{id: "5a2c769d4ef79d57e29c940a", pseudo: "sof", email: "sofiene@torepa.xyz", avatar: "ws5icnrjntmd4bbbvlay", tribu: {…}, …}
====================================
=========render userLogged==========
{id: "5a2c769d4ef79d57e29c940a", pseudo: "sof", email: "sofiene@torepa.xyz", avatar: "ws5icnrjntmd4bbbvlay", tribu: {…}, …}
====================================
remote-redux-devtools: Socket connection errors are being suppressed.
This can be disabled by setting suppressConnectErrors to 'false'.
SocketProtocolError {name: "SocketProtocolError", message: "Socket hung up", code: 1006, stack: "SocketProtocolError: Socket hung up↵ at SCSocke…a/node_modules/expo/tools/hashAssetFiles:2316:42)"}
=========render userLogged==========
null
====================================
[apollo-cache-persist] Persisted cache of size 90595 So after the first two renders, the cache is filled but at the end of the third it becomes empty. So user is logged during few milliseconds and is logout just after... And this problem does not appear on Android... On Android there only are two renders instead of three. [apollo-cache-persist] Restored cache of size 35420
=========render userLogged==========
Object {
"__typename": "User",
"avatar": "muv3zrworf6bg2mcap9o",
"email": "gexxxxbault@gmail.com",
(...)
}
====================================
=========render userLogged==========
Object {
"__typename": "User",
"avatar": "muv3zrworf6bg2mcap9o",
"email": "geraxxxxault@gmail.com",
(...)
},
}
====================================
[apollo-cache-persist] Persisted cache of size 33281 Really strange behavior... Versions :
|
I have probably hit this same problem. I have two queries called from two different screens. Both queries retrieve some combination of objects from server but one of them retrieves less attributes then the other one. What I noticed is that the queries need to be called in specific order for this bug to appear. Lets say I have two screens with two queries. Now following happens: Another scenario: From this I presume query A has to be loaded before query B is loaded for the A query to break. This is not the first time I run into this problem. Previously we solved it by using fragments to always load all the data, because it was not that big of a overhead. This time it is a bit larger problem, because there is lot more data. |
I'm also having trouble with this behavior |
@MrLoh Thank you for reporting the issue and digging into! I'm working on a reproduction: https://codesandbox.io/s/lyj02q5347. It seems like the query works for first order values under the root query, so we'll have to create a little more complicated repro. If you have a chance to fork the codesandbox and associated https://glitch.com/edit/#!/worried-song-1 to create a repro, that would be incredible!
|
I also ran into this issue (random, 20% of the time it still worked) when using the same child to 2 different object types.
This was fixed when I changed the __typename for user comment to be different from the __typename for order comment. |
Seems like adding the prop https://www.apollographql.com/docs/react/essentials/queries.html |
If anyone here is able to continue the work in #2920 (comment) and provide a runnable reproduction that shows this happening, that would be awesome! |
meet the question too query ProductGraph {
} I can only get id and name in relationships and related_nodes |
my current solution is use Aliases of graphql
that I can get the result _id and _name with the right value from graphql server and the return json property name would be _id and _name |
This has been addressed by #4743, and will be coming in Apollo Client 2.6. You can set |
I have a typical usecase where a mutation update inserts a new element in a list. Very similar to the standard example from the docs.
But the query is of course much more complicated. In my case I am creating a rating that has two 1-1 relation to a movie and a user object. The update function has to update both. The issue was when updating the user object by inserting the rating with the corresponding movie id on the users rating list. All that works great so far. But the issue was that the query where the users ratings are requested was reading more information from the movie object than what was already loaded for some movies. Now the query just returned null. I took me about a day to figure out that the one missing field was the issue.
To illustrate lets say this is the query on the user object that gets the ratings:
And this is the mutation
Now when another query had already loaded the movie poster into the cache all was well, but when the poster was missing the
userRatings
query simply returnednull
without any errors being shown. In reality it was quite hard to figure out what even had happened because everything seemed to work but on the user profile screen the data suddenly disappeared.Intended outcome:
I would have expected that there would be an error message from the
userRatings
query and that just the missing data would have been null but the rest there. Basically how a query to the server would behave. It seems that client side cache updates don't prduce errors in other queries.Actual outcome:
Nothing indicated that there was any error in apollo, the data simply disappeared. I am on react native, and the data disappeared on a different screen, making this very hard to track down as I first needed to find out that the mutation even caused this and because it just happened for movies where the poster wasn't already fetched by another query in the application.
Version
^1.1.4
^0.1.0
^2.0.4
The text was updated successfully, but these errors were encountered: