apollographql / apollo-client

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
https://apollographql.com/client
MIT License
19.39k stars 2.66k forks source link

Cannot read properties of undefined (reading 'data') #12053

Open julianCast opened 2 months ago

julianCast commented 2 months ago

Issue Description

Hi! We are getting these error randomly:

// node_modules/@apollo/client/react/hooks/useQuery.js in InternalState.prototype.toQueryResult at line 440:27
InternalState.prototype.toQueryResult = function (result) {
        var queryResult = this.toQueryResultCache.get(result);
        if (queryResult)
            return queryResult;
      // Next line, where result could be undefined ?
        var data = result.data, partial = result.partial, resultWithoutPartial = __rest(result, ["data", "partial"]);
        this.toQueryResultCache.set(result, (queryResult = __assign(__assign(__assign({ data: data },

Link to Reproduction

None

Reproduction Steps

No response

@apollo/client version

3.9.11

phryneas commented 2 months ago

All of that code has been rewritten from the ground in newer versions of Apollo Client - could you please update to a current version? :)

julianCast commented 2 months ago

All of that code has been rewritten from the ground in newer versions of Apollo Client - could you please update to a current version? :)

Oh! I'm updating now, thanks! I'll let you know the results after

Cattari commented 2 months ago

Guys, we are on the v3.11.4 and this code does not differ from the latest one (v3.11.8). But we are still getting the Cannot read properties of undefined (reading 'data') error.

Attaching the stacktrace (lines may be incorrect):

TypeError: Cannot read property 'data' of undefined at anonymous (address at /usr/local/var/jenkins/workspace/our_app/node_modules/@apollo/client/react/hooks/hooks.cjs:353:null) at complete (address at /usr/local/var/jenkins/workspace/our_app/node_modules/@apollo/client/react/hooks/hooks.cjs:199:null) at call (native) at notifySubscription (address at /usr/local/var/jenkins/workspace/our_app/node_modules/zen-observable/lib/Observable.js:153:null) at onNotify (address at /usr/local/var/jenkins/workspace/our_app/node_modules/zen-observable/lib/Observable.js:17:null) at complete (address at null:null:null) at anonymous (address at /usr/local/var/jenkins/workspace/our_app/node_modules/@apollo/client/utilities/utilities.cjs:1270:null) at forEach (native) at iterateObserversSafely (address at /usr/local/var/jenkins/workspace/our_app/node_modules/@apollo/client/utilities/utilities.cjs:1248:null)

I think we are getting the same error, I may be wrong. We are still investigating what is causing the issue. But if you think that the issue is here - we would be happy to get any feedback about this.

jerelmiller commented 2 months ago

@Cattari that looks very similar but its difficult to tell. If you're able to reproduce this, would you be able to put together a runnable reproduction for us? That would be super helpful to understanding whats happening here.

That result should never be undefined, but we haven't been able to pinpoint exactly why sometimes it is. We were hoping the useQuery rewrite with 3.11 would have helped, but alas seems that we still run into this issue from time to time.

phryneas commented 2 months ago

@Cattari line 353 of hooks.cjs in 3.11.4 is

    var globalDefaults = client.defaultOptions.watchQuery;

no access to data there. Are you sure you are on 3.11.4 and there's not also some other installation of @apollo/client thrown in the mix here?

To verify, try npm ls @apollo/client or yarn why @apollo/client, depending on the package manager you are using.

Cattari commented 2 months ago

@phryneas as I said, lines maybe wrong. I got this stacktrace from a symbolication from the release build in React Native. I checked the lining before, it's wrong. But the stacktrace with function naming and paths are correct. So, ignore the lines here, please.

The question is: May the result in toQueryResult function be undefined? If yes - then that's the issue.

phryneas commented 2 months ago

There are currently two code paths in useQuery to toQueryResult (the original InternalState.prototype.toQueryResult this issue was opened over doesn't exist anymore)

  const currentResultOverride = React.useMemo(
    () =>
      resultOverride &&
      toQueryResult(resultOverride, previousData, observable, client),
    [client, observable, resultOverride, previousData]
  );

As you can see, this does a check on resultOverride, so it cannot be undefined.

The other call is

  resultData.current = toQueryResult(
    unsafeHandlePartialRefetch(nextResult, observable, partialRefetch),
    resultData.previousData,
    observable,
    client
  );

And here, unsafeHandlePartialRefetch accesses properties on nextResult, so it would already crash before reaching toQueryResult.

There are two more call sites from useLazyQuery, so maybe we should narrow it down a bit: are you using useQuery or useLazyQuery here?

phryneas commented 2 months ago

Checking these real quick:

          toQueryResult(
            observable.getCurrentResult(),
            resultData.previousData,
            observable,
            client
          )

observable.getCurrentResult() never returns undefined.

This would only leave

    concast.subscribe({
      next: (value) => {
        result = value;
      },
      complete: () => {
        resolve(
          toQueryResult(result, resultData.previousData, observable, client)
        );
      },
    })

This could in theory have result undefined, if you have a link that prevents a next call and as a result, complete is called before complete.

Could that be the case?

julianCast commented 2 months ago

I believe result can be undefined when the request hook is interrupted, for example if while fetching we make a different request that will interrupt the previous one.

jerelmiller commented 2 months ago

Related: https://github.com/apollographql/apollo-client/issues/11846. I knew this looked familiar but couldn't find the issue until just moments ago 😅.

phryneas commented 2 months ago

I believe result can be undefined when the request hook is interrupted, for example if while fetching we make a different request that will interrupt the previous one.

That is an interesting thought, but I don't think that is the cause: An old request will only be cancelled if there are no more subscribers to the observable. useLazyQuery's execute function creates a subscription for the returned promise, so the request should never be cancelled. And for useQuery, this code path is never reached.

Related: https://github.com/apollographql/apollo-client/issues/11846. I knew this looked familiar but couldn't find the issue until just moments ago 😅.

Yeah, I also had that in mind, but we fixed that in 3.11.4, so it can't be that :/


I'm a bit out of ideas. Could you share a replay of this happening with one of us privately?

julianCast commented 2 months ago

I'm a bit out of ideas. Could you share a replay of this happening with one of us privately?

We are updating Apollo client first like you said, we are running tests now. Since it happens very often in one of our Cypress tests we'll soon know if it's fixed. I'll be back with the results. Thank you again

Cattari commented 2 months ago

Guys, we have an update. Sorry, for confusing. It was our fault. We were using fromPromise utility and our promise was returning undefined.

So, guys, who faces the same issue, make sure your promise you put inside fromPromise @apollo/client func does not return undefined.

@phryneas @julianCast FYI

puneetkansal04 commented 2 months ago
Screenshot 2024-09-25 at 12 02 01 PM

Getting same issue attaching a screenshot of IOS Simulator that may help to analyse it.

Error is like this TypeError: undefined is not an object (evaluating 'result.data')

@julianCast @Cattari @phryneas @jerelmiller have a look

jerelmiller commented 2 months ago

@puneetkansal04 what version of Apollo Client are you using?

puneetkansal04 commented 2 months ago

apollo version 3.11.8 @jerelmiller

jerelmiller commented 2 months ago

@puneetkansal04 any chance you could provide a reproduction of the issue? This one has been difficult to track down without a way to reproduce it since we haven't been able to narrow down why result can be undefined in the first place. Unfortunately the screenshot doesn't provide anything new to understand 🙁

puneetkansal04 commented 2 months ago

@jerelmiller for reproducing i think if you will hit multiple queries and then you will expire the token then in that queries i think you will get this error. Because i don't know deep about this.

jerelmiller commented 2 months ago

@puneetkansal04 I'm not sure what you mean by "expire the token". Can you explain further? Better yet, can you put together a reproduction? You can use our error template as a starting point to help demonstrate the issue.