Version 3.0.0 of the Firebase Admin SDK for Python introduces some important changes in the API. Primarily, the API changes in this release are additions and improvements in error handling for Auth, FCM, and other Firebase features.
General error handling changes
The following exception types have been removed:
auth.AuthError
db.ApiCallError
instance_id.ApiCallError
messaging.ApiCallError
project_management.ApiCallError
Instead, a new firebase_admin.exceptions
module has been introduced. Public
APIs in auth
, db
, instance_id
, messaging
and project_management
modules now raise instances of exceptions.FirebaseError
type.
# Before
from firebase_admin import messaging
try:
messaging.send(build_message())
except messaging.ApiCallError as ex:
print('Error message:', ex)
# v3
from firebase_admin import exceptions
from firebase_admin import messaging
try:
messaging.send(build_message())
except exceptions.FirebaseError as ex:
print('Error message:', ex)
print('Error code:', ex.code) # Platform-wide error code
print('HTTP response:', ex.http_response) # requests HTTP response object
The exceptions.FirebaseError
type has many subtypes. Public APIs in the Admin
SDK can only raise these subtypes. Therefore, you can write code that catches a
specific subtype and handles errors more granularly. For example:
try:
messaging.send(build_message())
except exceptions.InvalidArgumentError as ex:
print(ex) # One or more arguments were invalid
except exceptions.UnavailableError as ex:
print(ex) # FCM service is temporarily down
except exceptions.FirebaseError as ex:
print(ex) # All other errors
Instead of catching specific error types, it is also possible to catch the
parent FirebaseError
type and compare error codes.
try:
messaging.send(build_message())
except exceptions.FirebaseError as ex:
if ex.code == exceptions.INVALID_ARGUMENT:
print(ex) # One or more arguments were invalid
elif ex.code == exceptions.UNAVAILABLE:
print(ex) # FCM service is temporarily down
else:
print(ex) # All other errors
Each module may declare additional subtypes extending from the
exceptions.FirebaseError
parent type (see below).
General guideline for error handling: Catch exceptions.FirebaseError
when
you don’t need to differentiate between error conditions. Look for a more
specific error subclass or error code when you need to differentiate error
conditions.
Auth error handling changes
JWT Verification
The auth.verify_id_token()
method no longer raises ValueError
to indicate
token validation errors. Instead, you will get one of the following error types:
InvalidIdTokenError
ExpiredIdTokenError
RevokedIdTokenError
The InvalidIdTokenError
type extends the exceptions.InvalidArgumentError
type, which in turns extends the exceptions.FirebaseError
type.
ExpiredIdTokenError
and RevokedIdTokenError
extend InvalidIdTokenError
.
# Before
from firebase_admin import auth
try:
auth.verify_id_token(id_token, check_revoked=True)
except ValueError as ex:
print('Error message:', ex)
# v3
from firebase_admin import auth
# Coarse-grained error handling
try:
auth.verify_id_token(id_token, check_revoked=True)
except auth.InvalidIdTokenError as ex:
print('ID token is invalid, expired or revoked')
# Fine-grained error handling
try:
auth.verify_id_token(id_token, check_revoked=True)
except auth.RevokedIdTokenError as ex:
print('ID token has been revoked')
except auth.ExpiredIdTokenError as ex:
print('ID token is expired')
except auth.InvalidIdTokenError as ex:
print('ID token is invalid')
Similarly, the auth.verify_session_cookie()
method raises the following
exception types:
InvalidSessionCookieError
ExpiredSessionCookieError
RevokedSessionCookieError
Class hierarchy and semantics are similar to the verify_id_token()
API.
Custom tokens
The create_custom_token()
API raises auth.TokenSignError
instead of
ValueError
to indicate failures.
# Before
from firebase_admin import auth
try:
auth.create_custom_token(uid)
except ValueError as ex:
print('Error message:', ex)
# v3
from firebase_admin import auth
try:
auth.create_custom_token(uid)
except auth.TokenSignError as ex:
print('Error message:', ex)
User management
The following new error types have been introduced to the auth
module:
EmailAlreadyExistsError
InvalidDynamicLinkDomainError
PhoneNumberAlreadyExistsError
UidAlreadyExistsError
UnexpectedResponseError
UserNotFoundError
# Before
from firebase_admin import auth
try:
auth.get_user(uid)
except auth.AuthError as ex:
if ex.code == auth.USER_NOT_FOUND_ERROR:
print('Specified user does not exist')
else:
print('Something else went wrong')
# v3
from firebase_admin import auth
from firebase_admin import exceptions
try:
auth.get_user(uid)
except auth.UserNotFoundError as ex:
print('Specified user does not exist')
except exceptions.FirebaseError as ex:
print('Something else went wrong')
FCM Error handling changes
The following new error types have been introduced to the messaging
module.
QuotaExceededError
SenderIdMismatchError
ThirdPartyAuthError
UnregisteredError
# Before
from firebase_admin import messaging
try:
messaging.send(msg)
except messaging.ApiCallError as ex:
if ex.code == 'registration-token-not-registered':
print('Registration token has been unregistered')
elif ex.code == 'invalid-argument':
print('One or more arguments invalid')
else:
print('Something else went wrong')
# v3
from firebase_admin import exceptions
from firebase_admin import messaging
try:
messaging.send(msg)
except messaging.UnregisteredError as ex:
print('Registration token has been unregistered')
except exceptions.InvalidArgumentError as ex:
print('One or more arguments invalid')
except exceptions.FirebaseError as ex:
print('Something else went wrong')
User property deletion
It is no longer possible to delete properties display_name
, photo_url
,
phone_number
and custom_claims
by setting them to None
. Setting these to
None
leaves these properties unchanged. They must be explicitly set to
auth.DELETE_ATTRIBUTE
to delete them.
# Before
from firebase_admin import auth
auth.update_user(uid, display_name=None, photo_url=None)
# v3
from firebase_admin import auth
auth.update_user(
uid, display_name=auth.DELETE_ATTRIBUTE, photo_url=auth.DELETE_ATTRIBUTE)