App: Signing in with `exitTo` doesn't work
If you haven’t already, check out our contributing guidelines for onboarding!
Platform - version: Desktop web (all?)
Action Performed (reproducible steps):
- Sign in as normal
- Navigate to a report
- Click “Sign out”
- Note that there is an
exitToin the URL - Enter an email address to sign in
- Note that it hangs there forever
Expected Result: Expected to see password/2FC page
Actual Result: Hung with a spinner forever
Notes/Photos/Videos:

Logs - JS/Android/iOS (if applicable):
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 16 (5 by maintainers)
I was able to reproduce it only with switching tab and coming back to the sign in tab. I’m not sure if others, who reproduced it, switched the tab in the process, but this flow has 100% reproducibility (thanks, @TheRohitSharma).
There was a post in the Slack about new steps for contributors:
Even though I’m itching to write the pull request, I’ll post the solution first.
Steps to reproduce
The root cause
This is a combination of two issues.
When
ReportActionsViewis mounted, it adds an event listener for the app visibility change (remember the tab switching?)So on each app visibility change, the function
recordMaxActionwill be called, and it will send the request to the server to update last read action id.And when
ReportActionsViewis unmounting, it should remove this listener:The problem is
AppState.addEventListenerdoesn’t really return anything, sothis.visibilityChangeEventis undefined after subscription to the event. It means thatcomponentWillUnmountdoesn’t remove the listener.The listener is still active after the sign out.
When user switches to other tab and returns back to the sign in, the event triggers. After 3 seconds timeout, it sends the request. But user is signed out, so server responds with 407 code. API request function calls
handleExpiredAuthTokento try to relogin user.This is the place where other issue happens.
handleExpiredAuthTokenpauses the network queue and tries to sendAuthenticaterequest, using saved credentials. But user is signed out. Socredentialsobject is null. So accessingcredentials.autoGeneratedLoginandcredentials.autoGeneratedPasswordthrows an exception, which is not caught.So
handleExpiredAuthTokenends prematurely. But before it tried to send the request, it paused the Network Queue. And after the exception the queue is still on pause.Now user enters the email and presses “Continue” button.
fetchAccountDetailsrequest is added to the queue, but queue is on pause, so request will never be sent and “Continue” button forever hangs in loading state.https://user-images.githubusercontent.com/130532/103470075-10e73680-4d76-11eb-8578-94283f4d5c95.mp4
The fix
The fix should include:
credentialsobject, or something like this:ReportActionsView:Prevention of future issues
I’m not sure about it yet.
I could put the request in
handleExpiredAuthTokentotry-catchblock, but we already have the catch for the promise. So this approach would require some duplication of the catch code, because promise rejection will not be caught bytry-catch.I could wrap the whole function content with
Promise.try(() => { ... });and add the only one parentcatch, which would handle both promise rejections and params errors. That would be cleaner, but looks a bit weird to me.The cleanest way would be
async/awaitwithtry/catch, but you don’t use it anywhere in your code. So that probably makes the №2 approach the winner.