Skip to content

fix(auth): fix "Already resumed" crash in phone auth SMS auto-verification - #2447

Open
demolaf wants to merge 1 commit into
version-10.0.0-beta04from
fix/phone-auth-already-resumed
Open

fix(auth): fix "Already resumed" crash in phone auth SMS auto-verification#2447
demolaf wants to merge 1 commit into
version-10.0.0-beta04from
fix/phone-auth-already-resumed

Conversation

@demolaf

@demolaf demolaf commented Aug 13, 2026

Copy link
Copy Markdown
Member

Fixes #2446.

DefaultVerifier.verifyPhoneNumber adapted Firebase's OnVerificationStateChangedCallbacks — which can fire more than once per request — onto a single-shot suspendCoroutine, resuming the same continuation from onVerificationCompleted, onVerificationFailed and onCodeSent. On the SMS auto-retrieval path Firebase delivers onCodeSent and then onVerificationCompleted, so the second resume threw IllegalStateException: Already resumed on the main thread inside Firebase's own dispatcher, where nothing in the library can catch it. A single AtomicBoolean latch now lets the first callback resolve the continuation and drops later ones with a log line.

Switching to suspendCancellableCoroutine also made cancellation reachable for the first time, so verifyPhoneNumber now rethrows CancellationException rather than reporting it as an auth error, and clears a pending Loading state so navigating away mid-request can't leave the UI spinning.

Added PhoneAuthDefaultVerifierTest covering every callback ordering plus cancellation — verified the multi-callback cases fail on the old code and pass with the fix.

@demolaf
demolaf changed the base branch from master to version-10.0.0-beta04 August 13, 2026 14:29
gemini-code-assist[bot]

This comment was marked as off-topic.

@demolaf
demolaf force-pushed the fix/phone-auth-already-resumed branch 2 times, most recently from 19c6f52 to 655b983 Compare August 14, 2026 12:52
@demolaf

demolaf commented Aug 14, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves phone number verification by handling coroutine cancellation and multiple callbacks more robustly. It transitions from suspendCoroutine to suspendCancellableCoroutine and introduces an AtomicBoolean to prevent multiple callbacks from resuming the continuation. Additionally, user-initiated cancellation now clears the pending loading state and propagates the CancellationException directly rather than emitting an error state. Comprehensive unit tests have been added to cover these scenarios. The review feedback suggests registering an invokeOnCancellation listener to mark the operation as resolved upon cancellation, which prevents late-arriving callbacks from attempting to resume the cancelled continuation.

@demolaf
demolaf marked this pull request as ready for review August 14, 2026 13:48
@demolaf
demolaf force-pushed the fix/phone-auth-already-resumed branch from 655b983 to 233082c Compare August 14, 2026 14:03

@russellwheatley russellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crash is gone, but first-callback-wins still drops auto-retrieval on the path this PR is fixing.

.setCallbacks(object :
PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
if (!isResolved.compareAndSet(false, true)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This latch stops the crash, but it also drops the auto-retrieved credential on the exact path this PR is fixing. Firebase's SMS auto-retrieval order is onCodeSent then onVerificationCompleted, so the user lands on the code-entry screen after Firebase already verified them. The Verifier interface is single-shot, so you'll need a side channel (PhoneAuthScreen already signs in on SMSAutoVerified). Can you keep the latch for the crash, but still emit SMSAutoVerified when a late onVerificationCompleted arrives after onCodeSent?

@@ -136,12 +136,10 @@ internal suspend fun FirebaseAuthUI.verifyPhoneNumber(
}
}
} catch (e: CancellationException) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now the only provider that rethrows a raw CancellationException and resets to Idle. Everything else wraps it as AuthCancelledException and emits AuthState.Error. Rethrowing is closer to structured concurrency, but it's a one-off. Can you either match the other providers, or call out why phone verify is special?

* Clears a pending [AuthState.Loading] by resetting to [AuthState.Idle]. States written by
* another operation in the meantime are left untouched.
*/
internal fun clearLoadingState() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only skips non-Loading states, so a newer Loading from a resend or another in-flight call would get reset to Idle. The new test covers PasswordResetLinkSent, not a second Loading. Can you key this on the Loading this call actually wrote, or drop the "left untouched" claim in the doc comment if that's not actually guaranteed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phone Auth crashes with "Already resumed" in DefaultVerifier.onVerificationCompleted

2 participants