Cloud Functions failures on Android were wrapped in a generic ErrorException
with no domain/code, so callers could not classify them the way they can on
iOS (FIRFunctionsErrorDomain + gRPC status codes) or the way Firestore already
does here (FIRFirestoreErrorDomain).
Mirror the Firestore pattern: add FunctionsErrorDomain ("com.firebase.functions",
matching iOS), a FunctionsErrorCode enum (canonical gRPC codes 0โ16), and
asNSError(functionsException:). Both call() overloads now surface the mapped
NSError. The Android Code enum is declared in gRPC order, so its `ordinal` is
the code value (Firestore's Code exposes value(); Functions' does not).
Lets consumers detect e.g. unavailable(14)/deadlineExceeded(4) to treat a
Functions timeout / backend-unreachable as expected connectivity rather than
an actionable error.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EncjCGPMYW8P7TDqgoJpmD
Merged
marcprux pushed a commit that referenced this pull request
Jul 25, 2026Android auth failures reached Swift as a bare `ErrorException`. Its
`localizedDescription` is the generic bridge text ("The operation could not
be completed. (SwiftJNI.ThrowableError error 1.)"), so a caller could not
tell "wrong password" from "email already in use" โ and any message it
derived from the error was wrong. On iOS the same failures carry
`FIRAuthErrorDomain` plus a `FIRAuthErrorCode`, which is what cross-platform
callers key off.
`mapAuthNSError` now resolves `FirebaseAuthException.getErrorCode()` to the
matching `FIRAuthErrorCode` raw value and keeps the Android message in
`NSLocalizedDescriptionKey`, with a fallback on the exception class for
unknown codes. `FirebaseNetworkException` (not a FirebaseAuthException, no
error code) maps to `.networkError`. `AuthErrorCode` grows from one case to
the resolvable set.
The mapping was previously only applied on the completion-handler paths; the
`async throws` ones threw straight through. signIn(withEmail:),
createUser(withEmail:), sendPasswordReset(withEmail:),
User.sendEmailVerification(), User.reauthenticate(with:) and User.delete()
now go through it too.
Mirrors `asNSError(functionsException:)` in SkipFirebaseFunctions (#95) and
`asNSError(firestoreException:)` in SkipFirebaseFirestore.
Claude-Session: https://claude.ai/code/session_01MxxbQFDQyDkNvFMZaV5Aij
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>