recaptcha icon indicating copy to clipboard operation
recaptcha copied to clipboard

Uncaught (in promise) Timeout recaptcha__en.js

Open atulshrma91 opened this issue 6 years ago • 46 comments

Google captcha is working well but console show up the error after some time

atulshrma91 avatar Oct 03 '18 21:10 atulshrma91

Would you be able to provide a bit more information about how to reproduce this, please. Preferably a URL and instructions for what to do to see this error in the console.

rowan-m avatar Oct 03 '18 22:10 rowan-m

I can provide a partial stacktrace of this. Comes from production so it's mangled, though. Maybe it'll still point you to the right place...

Uncaught (in promise) timeout

setTimeout (async)
p @ recaptcha__en.js:99
(anonymous) @ recaptcha__en.js:306
CW @ recaptcha__en.js:306
Os @ recaptcha__en.js:482
(anonymous) @ recaptcha__en.js:484
Promise.catch (async)
Os @ recaptcha__en.js:483
ss @ recaptcha__en.js:489
qY.PN @ recaptcha__en.js:486
re @ recaptcha__en.js:490
t.reset @ main.8d559850.js:16
t.componentWillUnmount @ main.8d559850.js:16
Ho @ main.8d559850.js:73
Yo @ main.8d559850.js:73
$a @ main.8d559850.js:73
Xa @ main.8d559850.js:73
Ga @ main.8d559850.js:73
Qa @ main.8d559850.js:73
ts @ main.8d559850.js:73
Ln @ main.8d559850.js:73

In my case, it happens after the unmount of a React component that was presenting a recaptcha. It has been occurring consistently for a few months.

subvertallchris avatar Oct 15 '18 15:10 subvertallchris

react-google-recaptcha claims this issue live in here. It seems to be related to when the recaptcha is unmounted, at an undetermined time later, a timeout error occurs in the browser.

conways-glider avatar Oct 23 '18 16:10 conways-glider

Maybe there is a step missing in react-google-recaptcha when removing the widget. Here are the steps done to remove the widget properly :

  • Removing all nodes from the container use in the grecaptcha.render method
  • Use grecaptcha.reset to reset the widget

So the problem is that you get "Uncaught (in promise) timeout" error after some time after removing the widget. If the steps above are correct then the problem is probably due to recaptcha

TomPradat avatar Oct 31 '18 16:10 TomPradat

@TomPradat does the widget itself still need to be in the dom/exist when reset is called?

hartzis avatar Oct 31 '18 20:10 hartzis

Also reproducible in Angular 6 when component hosting the recaptcha widget is destroyed after successful recaptcha check.

pleinonen avatar Nov 01 '18 06:11 pleinonen

Yeah, it causing a lot false alarm..Please fix.

Goaty89 avatar Nov 01 '18 07:11 Goaty89

@TomPradat does the widget itself still need to be in the dom/exist when reset is called?

I wondered about that so i forked and try to call reset before unmounting from the dom but i still got the issue

TomPradat avatar Nov 01 '18 09:11 TomPradat

I am also reproducing this, in a blade template in composition with Vue.

setTimeout (async)    
  M @
  (anonymous) @
  G4 @
  next @
  (anonymous) @
  ig @
  Xe @
  Qa.send @
  gV @
  (anonymous) @
  (anonymous) @

fabianclain avatar Nov 15 '18 10:11 fabianclain

Any update on this? @rowan-m If you require more information on this bug, do let us know.

patelnav avatar Mar 06 '19 09:03 patelnav

EDIT: Nevermind. My comment below did not work, even though at first it looked it did.

I encountered this with an Angular app. There was a detail in the examples on the reCAPTCHA v2 docs page, that I just found. In one of the examples, you can see that they are capturing the result of the call to widget = ...render() and then whenever the form is submitted, they are calling reset() by passing to it the result of the render() call. I replicated this with my app and it worked. I no longer get the timeout console errors. It seems that just calling reset() without passing any parameters isn't actually reset the "default" widget as the docs state.

This is what I did, and so far it seems to be working without throwing the timeout error:

// This code is in TypeScript.
private renderedWidget: any;

// In some function, I call the render() on the global grecaptcha object.
this.rendered = window.grecaptcha.render(...);

/** 
* Later, after doing my async request, I reset the captcha like this for both success and failure scenarios.
* You can also call this when your component is unloaded/destroyed.
* If your component isn't unloaded after using the reCAPTCHA response 
* until the timeout period, you may receive the timeout
* error, so you should reset the widget as early as possible.
*/

...
window.grecaptcha.reset(this.rendered);
...

praneetloke avatar Mar 12 '19 18:03 praneetloke

Yeah, it takes a while before error appear, maybe 15-30 seconds or so. Maybe some internal timeout or something is triggered? Anyway, only 'fix' I could come up with is to reload the page, which sucks.

pleinonen avatar Mar 13 '19 05:03 pleinonen

I think I have another solution, though, it may be specific to Angular. I made a few observations since my last comment above and think I have a fairly stable solution now.

  • The Uncaught (in promise): Timeout comes from zone.js. This makes it seem that there is an unhandled promise timeout, which zone.js is bubbling-up.
  • Resetting the widget after using the response token is the right thing to do. However, doing so seems to be producing another error n is null sporadically along with the promise timeout error.

So I made two changes:

  • Run all functions of grecaptcha using NgZone's runOutsideAngular(), which prevents any errors from recaptcha bubbling-up to the main app itself. For example,
// Sample for an Angular app.
...
constructor(private zone: NgZone){}
...
...
this.zone.runOutsideAngular(() => window.recaptcha.render(...));
...
  • Call the reset() function outside any HTTP client subscriptions. That is, don't call reset() from within any RxJS subscriptions. (I forget the reason why I had to do this, but it was due to some weird errors)

With the above two changes, I believe I have the widget working in a stable manner in an Angular app. I believe you could apply similar semantics to a React or Vue app as well.

I do have to admit that not having access to the un-minified source for the JS client made things very difficult. I spent way too much time identifying traffic lights, crosswalks, and fire hydrants trying to get confirm that my changes made a difference. On top of that, this repo appears to only talk about the PHP client, and makes no mention of the JS client. I searched for a different repo that would have the JS client, but couldn't find one.

praneetloke avatar Mar 13 '19 17:03 praneetloke

I also have same error on unmounting component in react.js app.

JustFly1984 avatar Mar 14 '19 18:03 JustFly1984

I also encountered this; though from my tests it's happening when the iframe URL fails to load. I can reproduce by blocking network requests to: https://www.google.com/recaptcha/api2/anchor?* and waiting for the timeout.

I've just hit on a possible approach to handling the error: in the ready event, make an explicit call to execute and wrap this in a try/catch. I'm assuming that the library attempts to call execute internally on load and does nothing to handle timeout errors.

It would be nice not to have to hack around this issue - e.g. provide a timeout or error callback...

blindfish3 avatar Apr 01 '19 15:04 blindfish3

The issue is still there

JustFly1984 avatar Oct 03 '19 15:10 JustFly1984

Same here with plain JavaScript. Trying to remove the widget as @TomPradat said, getting the timeout after 15-30 Seconds :(

Code42Cate avatar Oct 07 '19 22:10 Code42Cate

I have get rid of recaptcha in all of my projects. Too much problems, and it seems it will break soon for everybody, since there is new requirements for http headers from new chrome

JustFly1984 avatar Oct 08 '19 00:10 JustFly1984

Hi all, I figured out the issue with Angular today. It seems that because Angular replaces the body of the document with its own content, it actually removes the recaptcha badge from the page. This badge is required for recaptcha to function properly, although it can be set to visibility: hidden; in CSS (just not display: none;).

My solution is in my Angular app's main.ts file, I added this to run after Angular's bootstrap:

platformBrowserDynamic().bootstrapModule( AppModule ).then(() => {
  // due to some issues with how recaptcha and angular interact,
  // we have to load the recaptcha script after angular bootstraps
  let node = document.createElement('script');
  node.src = 'https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY';
  node.async = true;
  node.defer = true;
  document.getElementsByTagName('head')[0].appendChild(node);
}

This ensures that the script is loaded after the page has loaded completely and Angular has finished initializing everything.

jaredtbates avatar Oct 11 '19 05:10 jaredtbates

We have seen this error too. The user reported that they left our SPA (React) open overnight (laptop hibernating) and in the morning they could not log in until they restarted their browser, though we (and they) have been unable to replicate it. Logs show them hitting this error on each login attempt.

We load the script once (<script src='...'>) for the lifetime of the SPA, and call execute() for each login attempt.

I notice a couple of react/grecaptcha npm packages inject via Javascript and wondered whether it that might avoid badge issues @computerwizjared mentioned hitting in Angular. However, it looks like react-google-recaptcha suffers anyway (https://github.com/dozoisch/react-google-recaptcha/issues/103) so maybe that wouldn't make any difference.

Perhaps since this happens when we call execute rather than spontaneously after an amount of time, I should open a new issue?

Stacktrace in case it is useful:

Timeout
(anonymous)       @ recaptcha__en.js:497
Promise.catch (async)
ST                @ recaptcha__en.js:496
CI                @ recaptcha__en.js:502
[our code from here]

j-mew-s avatar Dec 03 '19 11:12 j-mew-s

I also experience the same issue on my react app with invisible recaptcha V2. My flow is:

  1. Load the library with a callback in the URL: https://www.google.com/recaptcha/api.js?onload=recaptchaLoadCallback&render=explicit
  2. In the recaptchaLoadCallback, render recaptcha and include a callback in the options: `const widgetId = grecaptcha.render(domId, {... callback: callbackFn ... }
  3. On component load, in a react's useEffect hook, call window.grecaptcha.execute(widgetId.current)
  4. When the callbackFn is called get the token argument and submit my form with it. After that, perform grecaptcha.reset(widghetId)

What I tried:

  1. Made sure nothing in my callbackFn in step 4 throws errors.
  2. Tried to return a promise and resolve or reject it from the callbackFn
  3. Tried to both stop rendering and keep rendering the <div id={domId} /> where recaptcha is rendered in step 2. Stopping rendering in certain combos of other stuff caused an error be thrown about being unable to read styles of undefined etc. which is expected.
  4. Tried simply removing the DOM element where recaptcha is rendered before / after grecaptcha.reset(widgetId) with DOMNode.remove() to avoid the subtleties of react.

None of this helped to resolve the issue for now. Here is the stacktrace if it could be useful:

Uncaught (in promise) Timeout (h)
setTimeout (async)
f @ recaptcha__lt.js:115
(anonymous) @ recaptcha__lt.js:364
Mn @ recaptcha__lt.js:19
next @ recaptcha__lt.js:18
(anonymous) @ recaptcha__lt.js:19
EP @ recaptcha__lt.js:19
cx @ recaptcha__lt.js:18
Ww.send @ recaptcha__lt.js:364
(anonymous) @ recaptcha__lt.js:520
Promise.then (async)
V.bZ @ recaptcha__lt.js:520
a.H @ recaptcha__lt.js:365
(anonymous) @ recaptcha__lt.js:365
Mn @ recaptcha__lt.js:19
next @ recaptcha__lt.js:18
O @ recaptcha__lt.js:19
Promise.then (async)
Y @ recaptcha__lt.js:19
(anonymous) @ recaptcha__lt.js:19
EP @ recaptcha__lt.js:19
cx @ recaptcha__lt.js:18
Ww @ recaptcha__lt.js:364
(anonymous) @ recaptcha__lt.js:363
$6 @ recaptcha__lt.js:100
uz @ recaptcha__lt.js:99
KP.O @ recaptcha__lt.js:99
Show 24 more blackboxed frames

Gonusi avatar Jan 24 '20 07:01 Gonusi

I think I solved it: When you destroy Recaptcha component in your preferred JS framework, make sure you set window.grecaptcha = null window.recaptcha = null

After this you shouldn't see timeout error anymore.

gapipro avatar Jan 29 '20 15:01 gapipro

window.grecaptcha = null window.recaptcha = null

No, this doesn't solve the error.

JFGHT avatar Jan 30 '20 09:01 JFGHT

Additional thing to do is document.querySelectorAll(‘iframe[src*=recaptcha]’).forEach(a => a.remove())

gapipro avatar Jan 30 '20 10:01 gapipro

Same "problem" (working well, but error in console) with Divi WordPress Theme and recaptcha V3.

Kipperlenny avatar Jan 30 '20 10:01 Kipperlenny

I also encountered the same error in my react app while integrating the firebase's phone authentication.

Finally I tried the code below, but unfortunately same error continues to exist... ( I also removed the container element of the recaptcha from the virtual dom of react )

window.recaptchaVerifier.reset();
window.recaptchaVerifier.clear();
window.recaptchaVerifier = null;

rudral avatar Jan 30 '20 23:01 rudral

I solved my error by calling grecaptcha.execute only when submiting a form . I have an AngularJS app and i included the script inside index.html

<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script>

after doing so i used ng-click on a button on another html page and on the controller i wrote the function below

function _registerNewUser() {
            grecaptcha.ready(function () {
                grecaptcha.execute('YOUR_SITE_KEY', { action: 'register' }).then(function (token) {

                    $http.post(serviceBase + 'api/Google', { GoogleToken: token }).then(function (response) {
                        ............

                        
                    }, function (response) {
                        .........
                    });
                });
            });
        }

The Post request inside the execute of recaptcha is to verify the user's token. After implementing the Recaptcha with this way i was able to solve this issue. To my understanding the problem was on the onCallBack function mentioned in the URL of the index .

Regarding the callback function you can see on the Recaptcha page that google's suggestion is not to use the callback function but just in case you want to , you can implement it as it was implemented in the V2 Recaptcha.

Quotting Google :

Tips

  • grecaptcha.ready() runs your function when the reCAPTCHA library loads. To avoid race conditions with the api.js, include the api.js before your scripts that call grecaptcha, or continue to use the onload callback that's defined with the v2 API.
  • Try hooking the execute call to interesting or sensitive actions like Register, Password Reset, Purchase, or Play.

JChario avatar Mar 06 '20 15:03 JChario

Can we please get a fix for this? We've been working on a fix before this post and tbh, after coming back two years later and it still not fixed is quite saddening :( https://github.com/DethAriel/ng-recaptcha/issues/123

The repo owner of the link even describes and also says it resides in an unsolved promise in recaptcha__en.js, any update?

ErraticFox avatar Mar 27 '20 21:03 ErraticFox

I also had this console warning when debugging without server-side verification (call to Google API to verify if reCAPTCHA client response is valid). My implementation includes dynamically created element for every captcha necessary and is in plain JS so everyone can refer to. In my case app url is address of Node.js application for server-side verification. Solved my issue with code below: https://gist.github.com/ANTOSzbk/75ed7003e914162550f61399122a3bd4

ANTOSzbk avatar Mar 31 '20 19:03 ANTOSzbk

Some update?

ArmandoAssuncao avatar Jul 07 '20 21:07 ArmandoAssuncao