apollo-client: Error Observable cancelled prematurely get's thrown
Sorry that I cannot provide more info. I may get some time to try and reproduce this in codesandbox in the future, but for now I just wanted to have a linkable bug reference to put into our codebase. For now we have this hackfix in ErrorBoundary component to get around this:
componentDidCatch(error: Error) {
captureException(error)
if (error.message === 'Observable cancelled prematurely') {
console.warn(error) // this is an annoying error getting thrown by apollo client 3.3.x. Some future versions might be okay, but it's the safest to leave this here
// easiest to get this is to use login link on a user profile page and open it in incognito window, There it happens 100% of the times
location.reload() // slightly hacky, but we can't think of a better hotfix ATM
return
}
this.setState({ error })
}
Intended outcome: no error is thrown no matter how we mount/dismount providers. If this indeed happens when a provider is unmounted by react then it should be caught by apollo-client because at that point we really don’t care about these observables and their values at all.
Actual outcome: this error is thrown:
Uncaught Error: Observable cancelled prematurely
| ApolloError | @ | index.js:26
| (anonymous) | @ | QueryManager.js:535
| (anonymous) | @ | asyncMap.js:11
| (anonymous) | @ | asyncMap.js:11
| notifySubscription | @ | Observable.js:140
| flushSubscription | @ | Observable.js:121
| (anonymous) | @ | Observable.js:174
| (anonymous) | @ | Observable.js:73
| Promise.then (async) | |
| onNewData | @ | useBaseQuery.js:18
| error | @ | QueryData.js:240
| notifySubscription | @ | Observable.js:140
| onNotify | @ | Observable.js:179
| error | @ | Observable.js:240
| (anonymous) | @ | iteration.js:4
| iterateObserversSafely | @ | iteration.js:4
| error | @ | ObservableQuery.js:26
| (anonymous) | @ | iteration.js:4
| iterateObserversSafely | @ | iteration.js:4
| error | @ | Concast.js:35
| notifySubscription | @ | Observable.js:140
| onNotify | @ | Observable.js:179
| error | @ | Observable.js:240
| (anonymous) | @ | asyncMap.js:19
| Promise.then (async) | |
| (anonymous) | @ | asyncMap.js:11
| notifySubscription | @ | Observable.js:140
| flushSubscription | @ | Observable.js:121
| (anonymous) | @ | Observable.js:174
| (anonymous) | @ | Observable.js:73
| Promise.then (async) | |
| enqueue | @ | Observable.js:71
| onNotify | @ | Observable.js:173
| error | @ | Observable.js:240
| ../node_modules/@apollo/client/utilities/observables/Concast.js.Concast.deliverLastMessage | @ | Concast.js:86
| ../node_modules/@apollo/client/utilities/observables/Concast.js.Concast.addObserver | @ | Concast.js:97
| (anonymous) | @ | Concast.js:11
| Subscription | @ | Observable.js:197
| subscribe | @ | Observable.js:279
| (anonymous) | @ | asyncMap.js:37
| Subscription | @ | Observable.js:197
| subscribe | @ | Observable.js:279
| complete | @ | Concast.js:56
| notifySubscription | @ | Observable.js:145
| onNotify | @ | Observable.js:179
| complete | @ | Observable.js:245
| (anonymous) | @ | Observable.js:593
| (anonymous) | @ | Observable.js:73
| Promise.then (async) | |
| enqueue | @ | Observable.js:71
| (anonymous) | @ | Observable.js:585
| Subscription | @ | Observable.js:197
| subscribe | @ | Observable.js:279
| complete | @ | Concast.js:56
| ../node_modules/@apollo/client/utilities/observables/Concast.js.Concast.start | @ | Concast.js:79
| Concast | @ | Concast.js:71
| ../node_modules/@apollo/client/core/QueryManager.js.QueryManager.fetchQueryObservable | @ | QueryManager.js:580
| (anonymous) | @ | ObservableQuery.js:312
| ../node_modules/@apollo/client/core/Reobserver.js.Reobserver.reobserve | @ | Reobserver.js:18
| ../node_modules/@apollo/client/core/ObservableQuery.js.ObservableQuery.reobserve | @ | ObservableQuery.js:317
| ../node_modules/@apollo/client/core/ObservableQuery.js.ObservableQuery.onSubscribe | @ | ObservableQuery.js:294
| (anonymous) | @ | ObservableQuery.js:13
| Subscription | @ | Observable.js:197
| subscribe | @ | Observable.js:279
| ../node_modules/@apollo/client/react/data/QueryData.js.QueryData.startQuerySubscription | @ | QueryData.js:220
| ../node_modules/@apollo/client/react/data/QueryData.js.QueryData.getExecuteResult | @ | QueryData.js:150
| ../node_modules/@apollo/client/react/data/QueryData.js.QueryData.execute | @ | QueryData.js:98
| (anonymous) | @ | useBaseQuery.js:35
| useDeepMemo | @ | useDeepMemo.js:6
| useBaseQuery | @ | useBaseQuery.js:35
| useQuery | @ | useQuery.js:3
| useThrowingQuery | @ | useThrowingQuery.ts:18
| useLoginPageQuery | @ | LoginPage.codegen.tsx:157
| OauthLoginButtons | @ | OauthLoginButtons.tsx:36
| renderWithHooks | @ | react-dom.development.js:14985
| mountIndeterminateComponent | @ | react-dom.development.js:17811
| beginWork | @ | react-dom.development.js:19049
| beginWork$1 | @ | react-dom.development.js:23940
| performUnitOfWork | @ | react-dom.development.js:22776
| workLoopSync | @ | react-dom.development.js:22707
| renderRootSync | @ | react-dom.development.js:22670
| performSyncWorkOnRoot | @ | react-dom.development.js:22293
| (anonymous) | @ | react-dom.development.js:11327
| unstable_runWithPriority | @ | scheduler.development.js:646
| runWithPriority$1 | @ | react-dom.development.js:11276
| flushSyncCallbackQueueImpl | @ | react-dom.development.js:11322
| flushSyncCallbackQueue | @ | react-dom.development.js:11309
| scheduleUpdateOnFiber | @ | react-dom.development.js:21893
| dispatchAction | @ | react-dom.development.js:16139
| Promise.then (async) | |
| onNewData | @ | useBaseQuery.js:18
| next | @ | QueryData.js:230
| notifySubscription | @ | Observable.js:135
| onNotify | @ | Observable.js:179
| next | @ | Observable.js:235
| (anonymous) | @ | iteration.js:4
| iterateObserversSafely | @ | iteration.js:4
| next | @ | ObservableQuery.js:21
| (anonymous) | @ | iteration.js:4
| iterateObserversSafely | @ | iteration.js:4
| next | @ | Concast.js:24
| notifySubscription | @ | Observable.js:135
| onNotify | @ | Observable.js:179
| next | @ | Observable.js:235
| (anonymous) | @ | Observable.js:589
| (anonymous) | @ | Observable.js:73
| Promise.then (async) | |
| enqueue | @ | Observable.js:71
| (anonymous) | @ | Observable.js:585
| Subscription | @ | Observable.js:197
| subscribe | @ | Observable.js:279
| complete | @ | Concast.js:56
| ../node_modules/@apollo/client/utilities/observables/Concast.js.Concast.start | @ | Concast.js:79
| Concast | @ | Concast.js:71
| ../node_modules/@apollo/client/core/QueryManager.js.QueryManager.fetchQueryObservable | @ | QueryManager.js:580
| (anonymous) | @ | ObservableQuery.js:312
| ../node_modules/@apollo/client/core/Reobserver.js.Reobserver.reobserve | @ | Reobserver.js:18
| ../node_modules/@apollo/client/core/ObservableQuery.js.ObservableQuery.reobserve | @ | ObservableQuery.js:317
| listeners.add.oqListener | @ | QueryInfo.js:103
| (anonymous) | @ | QueryInfo.js:115
| ../node_modules/@apollo/client/core/QueryInfo.js.QueryInfo.notify | @ | QueryInfo.js:115
| (anonymous) | @ | QueryManager.js:447
| ../node_modules/@apollo/client/core/QueryManager.js.QueryManager.broadcastQueries | @ | QueryManager.js:447
| ../node_modules/@apollo/client/core/QueryManager.js.QueryManager.stopQuery | @ | QueryManager.js:433
| (anonymous) | @ | QueryManager.js:332
| Promise.finally (async) | |
| ../node_modules/@apollo/client/core/QueryManager.js.QueryManager.query | @ | QueryManager.js:332
| ../node_modules/@apollo/client/core/ApolloClient.js.ApolloClient.query | @ | ApolloClient.js:133
| (anonymous) | @ | loadCustomFonts.ts:113
| (anonymous) | @ | loadCustomFonts.codegen.tsx:64
| __async | @ | loadCustomFonts.codegen.tsx:64
| loadCustomFonts | @ | loadCustomFonts.ts:112
| transitionAppStateToLoggedIn | @ | sessionStore.ts:289
| AuthSuccess | @ | AuthSuccess.tsx:34
| renderWithHooks | @ | react-dom.development.js:14985
| updateFunctionComponent | @ | react-dom.development.js:17356
| beginWork | @ | react-dom.development.js:19063
| beginWork$1 | @ | react-dom.development.js:23940
| performUnitOfWork | @ | react-dom.development.js:22776
| workLoopSync | @ | react-dom.development.js:22707
| renderRootSync | @ | react-dom.development.js:22670
| performSyncWorkOnRoot | @ | react-dom.development.js:22293
| (anonymous) | @ | react-dom.development.js:11327
| unstable_runWithPriority | @ | scheduler.development.js:646
| runWithPriority$1 | @ | react-dom.development.js:11276
| flushSyncCallbackQueueImpl | @ | react-dom.development.js:11322
| flushSyncCallbackQueue | @ | react-dom.development.js:11309
| scheduleUpdateOnFiber | @ | react-dom.development.js:21893
| dispatchAction | @ | react-dom.development.js:16139
| Promise.then (async) | |
| onNewData | @ | useBaseQuery.js:18
| next | @ | QueryData.js:230
| notifySubscription | @ | Observable.js:135
| onNotify | @ | Observable.js:179
| next | @ | Observable.js:235
| (anonymous) | @ | iteration.js:4
| iterateObserversSafely | @ | iteration.js:4
| next | @ | ObservableQuery.js:21
| (anonymous) | @ | iteration.js:4
| iterateObserversSafely | @ | iteration.js:4
| next | @ | Concast.js:24
| notifySubscription | @ | Observable.js:135
| onNotify | @ | Observable.js:179
| next | @ | Observable.js:235
| (anonymous) | @ | asyncMap.js:13
| Promise.then (async) | |
| (anonymous) | @ | asyncMap.js:11
| notifySubscription | @ | Observable.js:135
| onNotify | @ | Observable.js:179
| next | @ | Observable.js:235
| (anonymous) | @ | iteration.js:4
| iterateObserversSafely | @ | iteration.js:4
| next | @ | Concast.js:24
| notifySubscription | @ | Observable.js:135
| onNotify | @ | Observable.js:179
| next | @ | Observable.js:235
| next | @ | bundle.esm.js:29
| notifySubscription | @ | Observable.js:135
| onNotify | @ | Observable.js:179
| next | @ | Observable.js:235
| (anonymous) | @ | batching.js:84
| (anonymous) | @ | batching.js:84
| next | @ | batching.js:82
| notifySubscription | @ | Observable.js:135
| onNotify | @ | Observable.js:179
| next | @ | Observable.js:235
| (anonymous) | @ | batchHttpLink.js:75
| Promise.then (async) | |
| (anonymous) | @ | batchHttpLink.js:74
| Subscription | @ | Observable.js:197
| subscribe | @ | Observable.js:279
| ../node_modules/@apollo/client/link/batch/batching.js.OperationBatcher.consumeQueue | @ | batching.js:72
| (anonymous) | @ | batching.js:105
How to reproduce the issue: I actually don’t know. This error is thrown on startup of our closed source app, so I cannot share the code. The app actually has 2 graphQL endpoints and we switch between them depending on the route where the user is and I think this error get’s thrown when one apollo provider is unmounted, but I cannot be sure.
Versions
System:
OS: Linux 5.4 Ubuntu 20.04.1 LTS (Focal Fossa)
Binaries:
Node: 12.18.4 - ~/.nvm/versions/node/v12.18.4/bin/node
Yarn: 1.22.4 - ~/.yarn/bin/yarn
npm: 6.14.6 - ~/.nvm/versions/node/v12.18.4/bin/npm
Browsers:
Chrome: 87.0.4280.141
Firefox: 84.0.2
npmPackages:
@apollo/client: ^3.3.7 => 3.3.7
@apollo/link-batch-http: ^2.0.0-beta.3 => 2.0.0-beta.3
@apollo/link-context: ^2.0.0-beta.3 => 2.0.0-beta.3
@apollo/link-error: ^2.0.0-beta.3 => 2.0.0-beta.3
@apollo/link-schema: ^2.0.0-beta.3 => 2.0.0-beta.3
@apollo/react-components: ^3.1.5 => 3.1.5
@apollo/react-testing: ^3.1.4 => 3.1.4
apollo-client: ^2.6.10 => 2.6.10
apollo-server: ^2.19.2 => 2.19.2
apollo-server-express: ^2.19.2 => 2.19.2
react-apollo-network-status: ^5.0.1 => 5.0.1
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 24
- Comments: 68 (14 by maintainers)
Commits related to this issue
- Implement a fix for the "ERROR Error: Observable cancelled prematurely" bug https://github.com/apollographql/apollo-client/issues/7608#issuecomment-882418482 — committed to matthewrc/apollo-client by matthewrc 3 years ago
- Implement a fix for the "ERROR Error: Observable cancelled prematurely" bug https://github.com/apollographql/apollo-client/issues/7608#issuecomment-882418482 — committed to matthewrc/apollo-client by matthewrc 3 years ago
- Use setTimeout instead of microtask to delay Concast cancellation. Inspired by @cornedor's comment: https://github.com/apollographql/apollo-client/issues/7608#issuecomment-882418482 Should help with... — committed to apollographql/apollo-client by benjamn 3 years ago
- Add basic regression test for issues #7608 and #9690. — committed to apollographql/apollo-client by benjamn 2 years ago
- Add basic regression test for issues #7608 and #9690. — committed to apollographql/apollo-client by benjamn 2 years ago
- Guarantee `Concast` cleanup without `Observable cancelled prematurely` rejection (#9701) Should fix/improve issues #7608 and #9690, and possibly others. — committed to apollographql/apollo-client by benjamn 2 years ago
- upgrades @apollo/client to 3.7.0-alpha.6 fixing apollographql/apollo-client#7608 — committed to georga-app/georga-client-react by timegrid 2 years ago
For us, it happens when you unmount and remount the sasme component really fast.
Experiencing the same thing in an Angular project, when navigating away from a page where a query is happening.
Any progress? This issue is a huge problem for me.
If it helps, I started getting this error after updating
@apollo/client 3.3.21 => 3.4.0
and still get it on the latest version 3.4.5.Thanks @capaj for posting your workaround, very useful.
To the Apollo folks, it seems to me like throwing an error and breaking the user’s app is a bit extreme for this type of issue (especially since it appear to only occur in production mode).
I have no knowledge of this codebase, but could this line not pass
true
as a second parameter to prevent throwing errors? Or are errors being thrown as a method of communication, and accidentally being allowed out into userland?eagerly waiting for a fix too…
I noticed this starting to happen in my Angular app. It generally happens on sign in. You immediately get booted out of the app and it throws the “Observable cancelled prematurely” message. Unfortunately, we cannot reproduce with certainty so it’s been a nightmare to try and replicate, much less fix.
Somewhat of a repro, with angular.
Can also confirm that
3.7.0-alpha.3
fixed theObservable cancelled prematurely
issue for me too.I am experiencing same issue. This had started with version Apollo Client 3.3.0. For now I had downgraded to Apollo Client 3.2.9. . I think that this issue is connected with this feature “Unsubscribing the last observer from an ObservableQuery will once again unsubscribe from the underlying network Observable in all cases, as in Apollo Client 2.x, allowing network requests to be cancelled by unsubscribing.” Witch was implemented in Apollo Client 3.3.0
@benjamn Thanks for your work, but the problem is still not solved, and it’s worse in the new versions, because before you could at least see the error and know that something was wrong, but now not even that. Could you re-add the error message? I have a temporary fix using the error
I’m cautiously optimistic this problem may be solved once and for all by #9701, which you can test by running
to get version
3.7.0-alpha.3
. If all goes well, these changes should be safe to release in 3.6.4, not waiting from v3.7, so please let us know if/when you have a chance to test the alpha!Did some digging and found something quite interesting:
We recently upgraded to use
react 18.0.0
, using@apollo/client 3.6.1
. One interesting thing with react 18 is its new development-only check inStrictMode
. ItReading the whole linked paragraph, it also says that this mount/unmount behavior will be a performance optimization feature and that it
This means that this will be a future problem in non-development react apps as well.
Since we use
StrictMode
for our app, this new mount/unmount behavior causes the problem for us for ouruseSubscription
hooks. When I removeStrictMode
, the subscription worked like a charm again! However, aside from debugging, that’s not an option because a) we want to useStrictMode
and b) as described above, this behavior is becoming a feature in react 18.@brainkim Do you already have a suitable repo for reproduction?
This issue could get fixed in the refactoring happening in #9331. But we’ll need a sign from core team for that PR to progress further.
I was having this problem, I read and research several things about that issue. Unfortunately, the issue is specific to your approach and codebase. You may have a memory leak or unexpected behavior on your product as a code. Already it proofs that because all these comments are pointing to different complaints.
@myth535 I have the same problem, the useSubscription sometimes works and sometimes don’t, feels unstable. I have to implement my own vanilla javascript subscription:
The subscription feels more stable and works well!
We believe this is now resolved in
@apollo/client@3.6.4
and later - let us know otherwise. Thanks!3.7.0-alpha.3
resolved the issue for me! Was stuck on v3.2.9 only because the later versions had this issue. Thanks for the fix, hope it is merged in the stable release soon.I am seeing this issue while using subscription with react-table.
I was facing this issue using
useSubsrciption
hook. Was usinguseSubscription
hook into a component which was mounting and then unmounting.Figured out the unmounting reason. So when I fixed and stopped unmounting behavior, the problem was solved for me.
For those who want to check mount and unmount behavior for your component, I am happy to provide you example snippet
Hi @ all. Came across this error on using
setVariables(myParams)
. As i usedrefetch(myParams)
it solved the problem. Maybe this helps some of you.v3.4.10 still boots me out of my app and throws the observable error. I downgraded to build 3.2.9, which seems to be the last build before the error was introduced.
I am seeing this when using react-router
<Redirect to={someRoute} />
. In my case, I run a GQL query to check the status of the user’s account, and in some cases I will redirect the user to a different page. The redirect will happen (url bar updated), but then the error will be thrown at some point during the rendering of the new route.Using capaj’s workaround fixes the issue for now, but it’s not an idea UX.
Switching the
Promise.resolve
for asetTimeout(()=>{}, 0)
at https://github.com/apollographql/apollo-client/blob/main/src/utilities/observables/Concast.ts#L181 resolves this issue for me. However, I’m not sure if this is a real fix, or that the error is simple suppressed now.We’re having the same issue on v.3.3.9. Reverting to 3.2.9 is not an option, because it starts throwing Invariant Violations. Any insight on how to fix this? I can confirm that the Apollo Client Provider is being mounted only ONCE and never re-mounted.
Having the same issue here. With me, it also seems to happen when the provider gets unmountend and mounted again.