Is there an existing issue for this?
Closest prior art, none of which covers this: #10055 (user cancel used to surface as unknown — fixed by typing it as canceled), #18172 (overlapping Apple requests — fixed in 6.4.0 by serialising and typing operation-not-allowed), #17813 (same surface symptom, closed as an app configuration error). This issue is about the remaining fall-through branch, which still destroys the error information.
Which plugins are affected?
Auth
Which platforms are affected?
iOS
Description
On iOS, signInWithProvider(AppleAuthProvider()) runs Sign in with Apple natively via the plugin's own ASAuthorizationController. When the flow fails, authorizationController:didCompleteWithError: maps the four typed ASAuthorizationError codes (1001 canceled, 1002 invalid-response, 1003 not-handled, 1004 failed) to useful Flutter error codes — but ASAuthorizationErrorUnknown (1000) and every other NSError domain fall through to convertToFlutterError:, which only extracts a code when FIRAuthErrorUserInfoNameKey is present. Native AuthenticationServices/AuthKit errors never carry that key, so the Dart side receives the literal fallback:
[firebase_auth/unknown] An unknown error has occurred.
NSError.domain, NSError.code, and any NSUnderlyingError are discarded. The only place the real error survives is the plugin's own NSLog(@"Sign in with Apple errored: %@", error) — visible in the Xcode console, unreachable in production.
Why this matters in production: fleet monitoring on a shipping app shows real users failing Sign in with Apple in under 500 ms with this opaque error. From Dart it is impossible to distinguish, for example:
com.apple.AuthenticationServices.AuthorizationError Code=1000 — commonly a device with no usable Apple ID session (user signed out of iCloud, restricted/managed Apple ID), where the right response is a targeted "check you're signed in to your Apple ID in Settings" message;
AKAuthenticationError Code=-7026 ("Told not to present authorization sheet") — a presentation conflict, where a retry works;
- anything else Apple decides to throw.
Cancellation (#10055) and request overlap (#18172) were both fixed by surfacing what actually happened; this fall-through branch is the last place where the information is destroyed instead.
Proposal — keep code: "unknown" for backward compatibility, but stop discarding the native identity. Something like:
case ASAuthorizationErrorUnknown:
default: {
NSError *underlying = error.userInfo[NSUnderlyingErrorKey];
NSString *detail =
[NSString stringWithFormat:@"%@ (Domain=%@ Code=%ld%@)",
error.localizedDescription.length > 0
? error.localizedDescription
: @"An unknown error has occurred.",
error.domain, (long)error.code,
underlying == nil
? @""
: [NSString stringWithFormat:
@", Underlying: Domain=%@ Code=%ld",
underlying.domain, (long)underlying.code]];
completion(nil, [FlutterError errorWithCode:@"unknown" message:detail details:nil]);
break;
}
(Equally happy with the domain/code going into details instead of the message if that's preferred.) I'm willing to submit a PR if maintainers agree with the direction.
Reproducing the issue
- On a physical device, sign out of the Apple Account (Settings → sign out), or use any device state where AuthenticationServices refuses the request without presenting the sheet.
- Call
FirebaseAuth.instance.signInWithProvider(AppleAuthProvider()).
- The call fails immediately. The Xcode console shows the full NSError via the plugin's NSLog; Dart receives only
[firebase_auth/unknown] An unknown error has occurred. with no way to recover the domain/code.
Any unrecognised ASAuthorizationController delegate error takes the same path.
Firebase Core version
4.11.0
Flutter Version
3.44.4 (stable)
Relevant Log Output
# Xcode console — the information that never reaches Dart:
Sign in with Apple errored: Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1000 "(null)"
# What Dart receives:
FirebaseAuthException([firebase_auth/unknown] An unknown error has occurred.)
Flutter dependencies
Expand Flutter dependencies snippet
firebase_core: 4.11.0
firebase_auth: 6.5.4
firebase_ui_auth: 3.0.1
firebase_ui_oauth_apple: 2.0.1
Additional context and comments
The typed ladder in didCompleteWithError has improved case by case (canceled in #10055's fix, operation-not-allowed via #18172) precisely because each shape became distinguishable. This change would do the same for the remaining bucket: everything currently labelled unknown would still be unknown, but carry Domain=… Code=… so apps can classify (the message format is already parseable the same way as the Code: N pattern some FIRAuth errors embed).
Is there an existing issue for this?
Closest prior art, none of which covers this: #10055 (user cancel used to surface as
unknown— fixed by typing it ascanceled), #18172 (overlapping Apple requests — fixed in 6.4.0 by serialising and typingoperation-not-allowed), #17813 (same surface symptom, closed as an app configuration error). This issue is about the remaining fall-through branch, which still destroys the error information.Which plugins are affected?
Auth
Which platforms are affected?
iOS
Description
On iOS,
signInWithProvider(AppleAuthProvider())runs Sign in with Apple natively via the plugin's ownASAuthorizationController. When the flow fails,authorizationController:didCompleteWithError:maps the four typedASAuthorizationErrorcodes (1001canceled, 1002invalid-response, 1003not-handled, 1004failed) to useful Flutter error codes — butASAuthorizationErrorUnknown(1000) and every other NSError domain fall through toconvertToFlutterError:, which only extracts a code whenFIRAuthErrorUserInfoNameKeyis present. Native AuthenticationServices/AuthKit errors never carry that key, so the Dart side receives the literal fallback:NSError.domain,NSError.code, and anyNSUnderlyingErrorare discarded. The only place the real error survives is the plugin's ownNSLog(@"Sign in with Apple errored: %@", error)— visible in the Xcode console, unreachable in production.Why this matters in production: fleet monitoring on a shipping app shows real users failing Sign in with Apple in under 500 ms with this opaque error. From Dart it is impossible to distinguish, for example:
com.apple.AuthenticationServices.AuthorizationError Code=1000— commonly a device with no usable Apple ID session (user signed out of iCloud, restricted/managed Apple ID), where the right response is a targeted "check you're signed in to your Apple ID in Settings" message;AKAuthenticationError Code=-7026("Told not to present authorization sheet") — a presentation conflict, where a retry works;Cancellation (#10055) and request overlap (#18172) were both fixed by surfacing what actually happened; this fall-through branch is the last place where the information is destroyed instead.
Proposal — keep
code: "unknown"for backward compatibility, but stop discarding the native identity. Something like:(Equally happy with the domain/code going into
detailsinstead of the message if that's preferred.) I'm willing to submit a PR if maintainers agree with the direction.Reproducing the issue
FirebaseAuth.instance.signInWithProvider(AppleAuthProvider()).[firebase_auth/unknown] An unknown error has occurred.with no way to recover the domain/code.Any unrecognised
ASAuthorizationControllerdelegate error takes the same path.Firebase Core version
4.11.0
Flutter Version
3.44.4 (stable)
Relevant Log Output
Flutter dependencies
Expand
Flutter dependenciessnippetAdditional context and comments
The typed ladder in
didCompleteWithErrorhas improved case by case (canceledin #10055's fix,operation-not-allowedvia #18172) precisely because each shape became distinguishable. This change would do the same for the remaining bucket: everything currently labelledunknownwould still beunknown, but carryDomain=… Code=…so apps can classify (the message format is already parseable the same way as theCode: Npattern some FIRAuth errors embed).