firebase
semver
>=9.0.0postconditions30functions30last verified2026-04-17coverage score81%Postconditions — what we check
- signInWithEmailAndPassword · auth-errorerrorWhenAny Firebase auth failure: invalid email (auth/invalid-email), wrong password (auth/wrong-password), user not found (auth/user-not-found), user disabled (auth/user-disabled), network failure (auth/network-request-failed), or too many requests (auth/too-many-requests).Throws
FirebaseError with code property. Common codes: auth/invalid-email, auth/wrong-password, auth/user-not-found, auth/user-disabled, auth/network-request-failed, auth/too-many-requests. FirebaseError extends Error with code: string and customData: object.Required handlingCaller MUST wrap await signInWithEmailAndPassword() in try-catch. Auth failures are common in production — invalid credentials, disabled accounts. Unhandled rejection crashes the process or returns 500 to the user. try { const credential = await signInWithEmailAndPassword(auth, email, password); return credential.user; } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/wrong-password') throw new Error('Invalid password'); if (error.code === 'auth/user-not-found') throw new Error('User not found'); } throw error; }costhighin prodimmediate exceptionusers seelost datavisibilityvisible - createUserWithEmailAndPassword · auth-errorerrorWhenAny Firebase auth failure: email already in use (auth/email-already-in-use), invalid email (auth/invalid-email), weak password (auth/weak-password), operation not allowed (auth/operation-not-allowed), or network failure.Throws
FirebaseError with code. Common codes: auth/email-already-in-use, auth/invalid-email, auth/weak-password, auth/operation-not-allowed, auth/network-request-failed.Required handlingCaller MUST wrap await createUserWithEmailAndPassword() in try-catch. Registration failures are expected (email conflicts, weak passwords). try { const credential = await createUserWithEmailAndPassword(auth, email, password); return credential.user; } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/email-already-in-use') throw new Error('Email taken'); if (error.code === 'auth/weak-password') throw new Error('Password too weak'); } throw error; }costhighin prodimmediate exceptionusers seelost datavisibilityvisible - signInWithPopup · auth-errorerrorWhenAny auth failure: popup blocked (auth/popup-blocked), user cancelled (auth/popup-closed-by-user), account exists with different credential (auth/account-exists-with-different-credential), network failure, or cancelled popup before completion (auth/cancelled-popup-request).Throws
FirebaseError with code. Common codes: auth/popup-blocked, auth/popup-closed-by-user, auth/account-exists-with-different-credential, auth/cancelled-popup-request, auth/network-request-failed.Required handlingCaller MUST wrap await signInWithPopup() in try-catch. Popup blocking is common — adblockers and browser settings frequently block popups. User cancellation is also a normal flow. try { const result = await signInWithPopup(auth, provider); return result.user; } catch (error) { if (error instanceof FirebaseError && error.code === 'auth/popup-blocked') { // Fallback to redirect or inform user } throw error; }costhighin prodimmediate exceptionusers seelost datavisibilityvisible - getDocs · firestore-errorerrorWhenAny Firestore failure: permission denied (permission-denied), network failure (unavailable), resource not found (not-found), invalid query arguments (invalid-argument), or unauthenticated (unauthenticated).Throws
FirebaseError with code. Common codes: permission-denied, unavailable, not-found, invalid-argument, unauthenticated, resource-exhausted (quota).Required handlingCaller MUST wrap await getDocs() in try-catch. Permission denied errors happen when Firestore Security Rules block access. Network failures occur in offline scenarios or during Firebase outages. try { const snapshot = await getDocs(q); return snapshot.docs.map(doc => doc.data()); } catch (error) { console.error('Firestore query failed:', error.message); throw error; }costhighin prodimmediate exceptionusers seelost datavisibilityvisible - addDoc · firestore-errorerrorWhenAny Firestore failure: permission denied, invalid data (undefined values, circular references), network failure, or quota exceeded.Throws
FirebaseError with code. Common codes: permission-denied, invalid-argument, unavailable, unauthenticated, resource-exhausted.Required handlingCaller MUST wrap await addDoc() in try-catch. Permission denied is common when users are not authenticated or Firestore Security Rules block writes. try { const docRef = await addDoc(collection(db, 'items'), data); return docRef.id; } catch (error) { console.error('Failed to add document:', error.message); throw error; }costhighin prodimmediate exceptionusers seelost datavisibilityvisible - setDoc · firestore-errorerrorWhenAny Firestore failure: permission denied, invalid data, network failure, or quota exceeded.Throws
FirebaseError with code. Common codes: permission-denied, invalid-argument, unavailable, unauthenticated, resource-exhausted.Required handlingCaller MUST wrap await setDoc() in try-catch. try { await setDoc(doc(db, 'users', userId), userData); } catch (error) { console.error('Failed to set document:', error.message); throw error; }costhighin prodimmediate exceptionusers seelost datavisibilityvisible - updateDoc · firestore-errorerrorWhenAny Firestore failure: document not found (not-found), permission denied, invalid data, network failure, or unauthenticated.Throws
FirebaseError with code. Common codes: not-found, permission-denied, invalid-argument, unavailable, unauthenticated.Required handlingCaller MUST wrap await updateDoc() in try-catch. updateDoc() throws not-found if the document doesn't exist (unlike setDoc). try { await updateDoc(docRef, { lastUpdated: new Date() }); } catch (error) { console.error('Failed to update document:', error.message); throw error; }costhighin prodimmediate exceptionusers seelost datavisibilityvisible - deleteDoc · firestore-errorerrorWhenAny Firestore failure: permission denied, network failure, or unauthenticated. (Does NOT throw if document doesn't exist.)Throws
FirebaseError with code. Common codes: permission-denied, unavailable, unauthenticated, resource-exhausted.Required handlingCaller MUST wrap await deleteDoc() in try-catch. try { await deleteDoc(doc(db, 'items', itemId)); } catch (error) { console.error('Failed to delete document:', error.message); throw error; }costhighin prodimmediate exceptionusers seelost datavisibilityvisible - sendPasswordResetEmail · auth-send-password-reset-invalid-emailerrorWhensendPasswordResetEmail() called without try-catch when email is invalid format or the Auth instance is misconfigured.Throws
FirebaseError with code: auth/invalid-email (malformed email address), auth/missing-email (empty email), auth/invalid-api-key (bad Firebase config), auth/network-request-failed (network failure), auth/too-many-requests (rate limit exceeded). Note: auth/user-not-found is NOT thrown when Email Enumeration Protection is enabled (the default since 2023) — Firebase returns success silently for unknown emails.Required handlingCaller MUST wrap await sendPasswordResetEmail() in try-catch. auth/invalid-email means client-side validation should run first. auth/too-many-requests means implement rate limiting in the UI. NEVER tell users whether the email exists — return generic "if account exists, email was sent". try { await sendPasswordResetEmail(auth, email); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/invalid-email') throw new Error('Invalid email format'); if (error.code === 'auth/too-many-requests') throw new Error('Too many attempts'); } throw error; }costmediumin prodimmediate exceptionusers seeauthentication failurevisibilitysilent - sendEmailVerification · auth-send-email-verification-errorerrorWhensendEmailVerification() called without try-catch.Throws
FirebaseError with code: auth/too-many-requests (sending too fast), auth/user-token-expired (user session expired — requires re-authentication), auth/network-request-failed (network failure), auth/user-disabled (account suspended), auth/invalid-user-token (user token invalid — session may be stale).Required handlingCaller MUST wrap await sendEmailVerification() in try-catch. auth/too-many-requests: Firebase limits verification email frequency — handle gracefully and inform user to wait before resending. auth/user-token-expired: User must sign in again before verification can be sent. try { await sendEmailVerification(user); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/too-many-requests') { throw new Error('Verification email already sent. Please wait before resending.'); } } throw error; }costlowin prodimmediate exceptionusers seeauthentication failurevisibilitysilent - deleteUser · auth-delete-user-requires-recent-loginerrorWhendeleteUser() called without try-catch when user has not recently authenticated.Throws
FirebaseError with code: auth/requires-recent-login (user's last sign-in was too long ago — must re-authenticate before this security-sensitive operation), auth/user-not-found (user was already deleted — race condition), auth/network-request-failed (network failure), auth/user-disabled (account was suspended).Required handlingCaller MUST wrap await deleteUser() in try-catch. auth/requires-recent-login is THE most important case: prompt user to sign in again using reauthenticateWithCredential() before retrying. This is the standard Firebase security pattern for sensitive operations. try { await deleteUser(user); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/requires-recent-login') { // Prompt re-authentication flow, then retry await reauthenticateWithCredential(user, credential); await deleteUser(user); } } throw error; }costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - signOut · auth-sign-out-errorwarningWhensignOut() called without try-catch.Throws
FirebaseError with code: auth/network-request-failed (network failure during token revocation), auth/internal-error (internal Firebase error, rare). Note: signOut() clears local auth state even if the server request fails, so users are effectively signed out locally even on error.Required handlingCaller MUST wrap await signOut() in try-catch to prevent unhandled rejections. Network failures during signOut are rare but possible. The local session is cleared regardless, so handle gracefully (log the error, redirect to login page). try { await signOut(auth); router.push('/login'); } catch (error) { // Sign out failed on server, but local session is cleared console.error('Sign out error:', error); router.push('/login'); // Redirect regardless }costlowin prodimmediate exceptionusers seeservice unavailablevisibilitysilentSources[20] - getIdToken · auth-get-id-token-expirederrorWhengetIdToken() called without try-catch when user session is expired or revoked.Throws
FirebaseError with code: auth/user-token-expired (token expired and cannot be refreshed — user must sign in again), auth/user-disabled (account suspended while token was valid), auth/user-not-found (user deleted), auth/network-request-failed (network failure during token refresh), auth/invalid-user-token (token is malformed).Required handlingCaller MUST wrap await getIdToken() in try-catch. auth/user-token-expired is the most common case — user session invalidated (password changed, token revoked from console, user deleted). On token errors, sign the user out and redirect to login. try { const token = await getIdToken(user); // Use token in Authorization header return fetch('/api/...', { headers: { Authorization: `Bearer ${token}` } }); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/user-token-expired' || error.code === 'auth/user-not-found') { await signOut(auth); router.push('/login'); } } throw error; }costhighin prodimmediate exceptionusers seeservice unavailablevisibilitysilentSources[21] - updateEmail · auth-update-email-requires-recent-loginerrorWhenupdateEmail() called without try-catch when user session is stale.Throws
FirebaseError with code: auth/requires-recent-login (must re-authenticate before changing email — security requirement), auth/email-already-in-use (email taken by another account), auth/invalid-email (malformed email), auth/operation-not-allowed (Email Enumeration Protection enabled — use verifyBeforeUpdateEmail instead), auth/network-request-failed (network failure).Required handlingCaller MUST wrap await updateEmail() in try-catch. auth/requires-recent-login is the most common error — prompt re-authentication. IMPORTANT: auth/operation-not-allowed means Email Enumeration Protection is enabled (default since 2023) — migrate to verifyBeforeUpdateEmail() which is the secure alternative. try { await updateEmail(user, newEmail); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/requires-recent-login') { throw new Error('Please sign in again to change your email'); } if (error.code === 'auth/email-already-in-use') { throw new Error('Email already in use'); } } throw error; }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - updatePassword · auth-update-password-errorerrorWhenupdatePassword() called without try-catch.Throws
FirebaseError with code: auth/requires-recent-login (must re-authenticate — changing passwords is a security-sensitive operation), auth/weak-password (password too short, usually < 6 characters), auth/network-request-failed (network failure), auth/user-disabled (account suspended).Required handlingCaller MUST wrap await updatePassword() in try-catch. auth/requires-recent-login requires prompting the user to sign in again. auth/weak-password should be caught with client-side validation first. try { await updatePassword(user, newPassword); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/requires-recent-login') { throw new Error('Please sign in again to change your password'); } if (error.code === 'auth/weak-password') { throw new Error('Password must be at least 6 characters'); } } throw error; }costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible - confirmPasswordReset · auth-confirm-password-reset-errorerrorWhenconfirmPasswordReset() called without try-catch when the reset code is invalid or expired.Throws
FirebaseError with code: auth/expired-action-code (reset link older than 1 hour — user must request a new one), auth/invalid-action-code (malformed or already-used code), auth/user-not-found (account deleted since reset was requested), auth/user-disabled (account suspended), auth/weak-password (new password too short), auth/network-request-failed (network failure).Required handlingCaller MUST wrap await confirmPasswordReset() in try-catch. auth/expired-action-code is the most common error — reset links expire after 1 hour. Prompt the user to request a new reset email. auth/invalid-action-code may mean the link was already used (single-use codes). try { await confirmPasswordReset(auth, oobCode, newPassword); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/expired-action-code') { throw new Error('Reset link has expired. Please request a new one.'); } if (error.code === 'auth/invalid-action-code') { throw new Error('Reset link is invalid or has already been used.'); } } throw error; }costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisibleSources[26] - getDoc · firestore-get-doc-errorerrorWhengetDoc() called without try-catch.Throws
FirebaseError (FirestoreError) with code: permission-denied (Firestore Security Rules block access), unavailable (network failure or Firebase outage — may resolve after retry), unauthenticated (user not signed in when rules require auth), not-found (collection or database doesn't exist — not thrown for missing docs). IMPORTANT: Returns empty DocumentSnapshot (snapshot.exists() === false) for missing documents — does NOT throw. Check snapshot.exists() before accessing snapshot.data().Required handlingCaller MUST wrap await getDoc() in try-catch AND check snapshot.exists() before access. permission-denied is very common during development (Firestore rules misconfigured). Failing to check exists() causes data() to return undefined, causing null reference errors. try { const snapshot = await getDoc(doc(db, 'users', userId)); if (!snapshot.exists()) { throw new Error('User not found'); } return snapshot.data(); } catch (error) { if (error instanceof FirebaseError) { console.error('Firestore read failed:', error.code, error.message); } throw error; }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent - runTransaction · firestore-transaction-contentionerrorWhenrunTransaction() called without try-catch when there is high write contention or the transaction function throws.Throws
FirebaseError (FirestoreError) with code: aborted (failed to commit after 5 retries due to high write contention), permission-denied (Security Rules block a read or write inside the transaction), unavailable (network failure), failed-precondition (transaction read document that no longer exists), resource-exhausted (quota exceeded), invalid-argument (more than 500 writes in one transaction). Also re-throws any error thrown inside the updateFunction.Required handlingCaller MUST wrap await runTransaction() in try-catch. aborted after 5 retries is the most critical case — indicates hot document (high contention). Consider sharding the counter or using FieldValue.increment() instead of transactions for counters. Errors thrown inside updateFunction propagate as-is — wrap with custom errors for clarity. try { const result = await runTransaction(db, async (t) => { const docSnap = await t.get(docRef); if (!docSnap.exists()) throw new Error('Document not found'); t.update(docRef, { count: docSnap.data().count + 1 }); return docSnap.data().count + 1; }); return result; } catch (error) { if (error instanceof FirebaseError && error.code === 'aborted') { throw new Error('Transaction failed after retries — high contention on document'); } throw error; }costhighin prodimmediate exceptionusers seelost datavisibilitysilent - uploadBytes · storage-upload-bytes-errorerrorWhenuploadBytes() called without try-catch.Throws
StorageError (extends FirebaseError) with code: storage/unauthorized (Security Rules block the upload — user not authenticated or path not allowed), storage/quota-exceeded (Firebase Storage quota for the project exceeded), storage/canceled (upload was cancelled), storage/retry-limit-exceeded (network too slow or unstable, max retries reached), storage/invalid-checksum (data corrupted in transit), storage/unauthenticated (no authenticated user). StorageError.code is prefixed with 'storage/'.Required handlingCaller MUST wrap await uploadBytes() in try-catch. storage/unauthorized is the most common error — check Firebase Storage Security Rules. storage/quota-exceeded requires checking Firebase project billing/quota limits. storage/retry-limit-exceeded indicates persistent network issues. try { const result = await uploadBytes(storageRef, file); return result.ref.fullPath; } catch (error) { if (error instanceof StorageError) { if (error.code === 'storage/unauthorized') { throw new Error('Not authorized to upload files'); } if (error.code === 'storage/quota-exceeded') { throw new Error('Storage quota exceeded'); } } throw error; }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - getDownloadURL · storage-get-download-url-errorerrorWhengetDownloadURL() called without try-catch.Throws
StorageError (extends FirebaseError) with code: storage/object-not-found (file was deleted or path is wrong — very common bug when referencing stale paths), storage/unauthorized (Security Rules deny read access), storage/no-download-url (file exists but has no public download URL — requires making the bucket public or using signed URLs), storage/bucket-not-found (wrong bucket name in Firebase config), storage/unauthenticated (rules require auth).Required handlingCaller MUST wrap await getDownloadURL() in try-catch. storage/object-not-found is the most common error — file was deleted, moved, or the stored path is wrong (race condition between upload and read is common). Validate file existence before serving download URLs to users. try { const url = await getDownloadURL(ref(storage, filePath)); return url; } catch (error) { if (error instanceof StorageError) { if (error.code === 'storage/object-not-found') { throw new Error('File not found'); } if (error.code === 'storage/unauthorized') { throw new Error('Not authorized to access this file'); } } throw error; }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent - signInWithEmailLink · email-link-expired-or-invaliderrorWhensignInWithEmailLink() called without try-catch. The email link has expired or was already used, or the link doesn't match the email address provided.Throws
FirebaseError with code: auth/expired-action-code (link expired — 10 minute TTL), auth/invalid-action-code (link already used or malformed), auth/invalid-email (email doesn't match the one the link was sent to), auth/user-disabled (account disabled after link was sent), auth/network-request-failed (network failure).Required handlingCaller MUST wrap await signInWithEmailLink() in try-catch. Expired and already-used links are the most common production failures — users often click links multiple times or wait too long. Each link is single-use and has a 10-minute expiration. try { const result = await signInWithEmailLink(auth, email, window.location.href); window.localStorage.removeItem('emailForSignIn'); return result.user; } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/expired-action-code') { throw new Error('Sign-in link has expired. Please request a new one.'); } if (error.code === 'auth/invalid-action-code') { throw new Error('Sign-in link already used. Please request a new one.'); } if (error.code === 'auth/invalid-email') { throw new Error('Email does not match the sign-in link.'); } } throw error; }costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible - signInAnonymously · anonymous-auth-not-enabled-or-quota-exceedederrorWhensignInAnonymously() called without try-catch. Anonymous auth not enabled in Firebase Console, or quota for anonymous accounts exceeded.Throws
FirebaseError with code: auth/operation-not-allowed (anonymous authentication not enabled in Firebase Console — frequent misconfiguration in new projects), auth/quota-exceeded (new anonymous sign-ups rate-limited, common when deployed to production without proper settings), auth/network-request-failed (network failure).Required handlingCaller MUST wrap await signInAnonymously() in try-catch. auth/operation-not-allowed means Anonymous sign-in is disabled in Firebase Console — developers often forget to enable it for new environments (staging, production). auth/quota-exceeded means Firebase is rate-limiting new anonymous sign-ups. try { const result = await signInAnonymously(auth); return result.user; } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/operation-not-allowed') { throw new Error('Anonymous sign-in is disabled. Enable it in Firebase Console.'); } if (error.code === 'auth/quota-exceeded') { throw new Error('Too many anonymous sign-in attempts. Please try again later.'); } } throw error; }costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible - updateProfile · update-profile-errorwarningWhenupdateProfile() called without try-catch. User's token expired, user was deleted, or network failure.Throws
FirebaseError with code: auth/network-request-failed (network failure during profile update — common in flaky connections), auth/user-token-expired (user's auth token has expired, requires re-authentication), auth/user-not-found (user account was deleted between sign-in and the profile update call).Required handlingCaller MUST wrap await updateProfile() in try-catch. auth/user-token-expired requires the user to sign in again. This function is commonly called immediately after createUserWithEmailAndPassword() in onboarding flows — both should be wrapped together. try { await updateProfile(auth.currentUser, { displayName: name, photoURL: avatarUrl }); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/network-request-failed') { throw new Error('Network error updating profile. Please try again.'); } if (error.code === 'auth/user-token-expired') { throw new Error('Session expired. Please sign in again.'); } } throw error; }costlowin prodimmediate exceptionusers seelost datavisibilitysilent - linkWithCredential · link-credential-conflicterrorWhenlinkWithCredential() called without try-catch. The credential is already associated with another Firebase account, or an account with that email already exists.Throws
FirebaseError with code: auth/credential-already-in-use (the credential is already linked to a different Firebase user account — cannot link the same Google/GitHub account to multiple Firebase users), auth/account-exists-with-different-credential (an account with the same email already exists but uses a different sign-in method — e.g. user has email/password account and tries to link Google with same email), auth/email-already-in-use (for email/password credential linking when email is taken), auth/provider-already-linked (user already has this provider linked), auth/requires-recent-login (security-sensitive operation requires recent sign-in).Required handlingCaller MUST wrap await linkWithCredential() in try-catch. auth/credential-already-in-use is the most important case — the linked credential's user needs to be merged or the conflict resolved. auth/account-exists-with-different-credential is very common in social auth flows where users try to link an OAuth account that matches an existing email/password account. try { const result = await linkWithCredential(user, credential); return result.user; } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/credential-already-in-use') { throw new Error('This account is already linked to another user.'); } if (error.code === 'auth/account-exists-with-different-credential') { throw new Error('An account with this email already exists with a different sign-in method.'); } if (error.code === 'auth/requires-recent-login') { throw new Error('Please sign in again before linking accounts.'); } } throw error; }costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible - reauthenticateWithCredential · reauth-credential-errorerrorWhenreauthenticateWithCredential() called without try-catch. Wrong password, stale credential, or user mismatch.Throws
FirebaseError with code: auth/wrong-password (incorrect password for email/password credential — user mistyped current password), auth/user-mismatch (credential does not correspond to the currently signed-in user — wrong account), auth/invalid-credential (the auth credential is malformed or has expired — OAuth token expired), auth/user-not-found (user account was deleted), auth/network-request-failed (network failure during re-auth).Required handlingCaller MUST wrap await reauthenticateWithCredential() in try-catch. This is required before deleteUser() or updateEmail() — if it fails, the subsequent sensitive operation must not proceed. auth/wrong-password is the most common failure. auth/user-mismatch means the credentials don't belong to the current user. const credential = EmailAuthProvider.credential(email, currentPassword); try { await reauthenticateWithCredential(auth.currentUser, credential); // Now safe to call deleteUser() or updateEmail() } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/wrong-password') { throw new Error('Current password is incorrect.'); } if (error.code === 'auth/user-mismatch') { throw new Error('Credential does not match the current user.'); } } throw error; }costmediumin prodimmediate exceptionusers seeauthentication failurevisibilityvisible - verifyBeforeUpdateEmail · verify-before-update-email-errorerrorWhenverifyBeforeUpdateEmail() called without try-catch. Email already in use, requires recent login, or network failure.Throws
FirebaseError with code: auth/email-already-in-use (new email already registered to another account), auth/requires-recent-login (security-sensitive operation — user must have signed in within the last few minutes), auth/invalid-email (new email address is malformed), auth/network-request-failed (network failure during verification email send), auth/operation-not-allowed (email/password accounts not enabled — unlikely but possible in Identity Platform configs).Required handlingCaller MUST wrap await verifyBeforeUpdateEmail() in try-catch. auth/requires-recent-login is the most common failure — the user must reauthenticate before changing their email. auth/email-already-in-use means the new email is taken. try { await verifyBeforeUpdateEmail(auth.currentUser, newEmail); // Tell user to check their new email inbox } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'auth/email-already-in-use') { throw new Error('This email address is already registered.'); } if (error.code === 'auth/requires-recent-login') { throw new Error('Please sign in again before changing your email.'); } } throw error; }costlowin prodimmediate exceptionusers seeauthentication failurevisibilitysilent - writeBatch.commit · batch-commit-permission-deniederrorWhenbatch.commit() called without try-catch. Firestore Security Rules deny one or more writes in the batch, or the batch exceeds 500 operations.Throws
FirebaseError (FirestoreError) with code: permission-denied (Security Rules block one or more write operations in the batch — the entire batch fails atomically), not-found (a batch.update() or batch.delete() references a document that does not exist), resource-exhausted (batch exceeds 500 operations or rate limits), unavailable (Firestore temporarily unavailable — transient network/service issue), unauthenticated (user not authenticated and rules require auth). The WriteBatch.commit() Promise will never resolve while offline.Required handlingCaller MUST wrap await batch.commit() in try-catch. A single permission-denied write in the batch fails ALL writes atomically. Check that all document paths in the batch pass Security Rules before committing. Monitor for resource-exhausted if batches dynamically grow with user-generated content. const batch = writeBatch(db); batch.set(doc(db, 'users', userId), userData); batch.update(doc(db, 'counters', 'users'), { count: increment(1) }); try { await batch.commit(); } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'permission-denied') { throw new Error('Not authorized to perform this update.'); } if (error.code === 'resource-exhausted') { throw new Error('Batch too large or rate limit exceeded. Reduce batch size.'); } } throw error; }costhighin prodimmediate exceptionusers seelost datavisibilitysilent - getCountFromServer · count-from-server-errorwarningWhengetCountFromServer() called without try-catch. Firestore Security Rules deny the query, or the underlying index is not ready.Throws
FirebaseError (FirestoreError) with code: permission-denied (Security Rules deny the underlying query the count is based on — common when the query has compound filters that require field-level auth), unauthenticated (user not authenticated and Security Rules require auth), failed-precondition (composite index not yet built for the query — very common during development when adding new queries), resource-exhausted (project quota exceeded or too many reads in short window), unavailable (Firestore temporarily unavailable).Required handlingCaller MUST wrap await getCountFromServer() in try-catch. failed-precondition with a message about missing indexes is very common during development — Firestore will include the index creation URL in the error message. permission-denied occurs when Security Rules don't allow the underlying collection read. try { const snapshot = await getCountFromServer(query(collection(db, 'orders'), where('userId', '==', userId))); return snapshot.data().count; } catch (error) { if (error instanceof FirebaseError) { if (error.code === 'permission-denied') { throw new Error('Not authorized to count this collection.'); } if (error.code === 'failed-precondition') { throw new Error('Missing Firestore index. Check Firebase Console.'); } } throw error; }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent - deleteObject · delete-object-errorerrorWhendeleteObject() called without try-catch. File does not exist, or Security Rules deny the delete operation.Throws
StorageError (extends FirebaseError) with code: storage/object-not-found (file was already deleted or path is wrong — concurrent deletion is common in user-facing apps where users can delete from multiple sessions), storage/unauthorized (Security Rules deny the delete — user does not own the file or rules require ownership check), storage/unauthenticated (user is not authenticated but rules require auth), storage/retry-limit-exceeded (network failure with all retries exhausted).Required handlingCaller MUST wrap await deleteObject() in try-catch. storage/object-not-found should be treated as a success (idempotent delete is safe) or at minimum should not crash the user-facing operation. Always check Security Rules: rules must verify file ownership to prevent users deleting others' files. try { await deleteObject(ref(storage, filePath)); } catch (error) { if (error instanceof StorageError) { if (error.code === 'storage/object-not-found') { // File already deleted — treat as success for idempotent delete return; } if (error.code === 'storage/unauthorized') { throw new Error('Not authorized to delete this file.'); } } throw error; }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent - httpsCallable · functions-call-unauthenticated-or-permission-deniederrorWhenhttpsCallable(functions, name) result called without try-catch. User not authenticated, permission denied, function not found, or internal server error.Throws
FunctionsError (extends FirebaseError) with code: functions/unauthenticated (function requires Firebase Authentication and user is not signed in), functions/permission-denied (user is signed in but does not have permission to call this function — typically enforced via Firebase Auth claims check in the function), functions/not-found (function does not exist or was not deployed — common during development), functions/internal (unhandled exception in the Cloud Function — function threw an error not wrapped in HttpsError), functions/unavailable (Cloud Functions temporarily unavailable — transient), functions/deadline-exceeded (function execution timeout — 60s default), functions/resource-exhausted (quota exceeded — max concurrent calls reached).Required handlingCaller MUST wrap await fn(data) in try-catch, NOT await httpsCallable() itself. functions/unauthenticated means the user must sign in before calling the function. functions/internal means the Cloud Function itself crashed — check server logs. functions/permission-denied is an application-level authorization failure. Use error.code to distinguish user-facing errors from internal server errors. const sendInvite = httpsCallable(functions, 'sendInvite'); try { const result = await sendInvite({ email, organizationId }); return result.data; } catch (error) { if (error instanceof FunctionsError) { if (error.code === 'functions/unauthenticated') { throw new Error('Please sign in to perform this action.'); } if (error.code === 'functions/permission-denied') { throw new Error('You do not have permission to perform this action.'); } if (error.code === 'functions/internal') { throw new Error('Server error. Please try again later.'); } } throw error; }costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
Sources
Every postcondition cites at least one of these. Numbered to match the footnotes above.
- [1]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#signinwithemailandpassword
- [2]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/password-auth
- [3]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#createuserwithemailandpassword
- [4]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#signinwithpopup
- [5]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/google-signin
- [6]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_.md#getdocs
- [7]firebase.google.com/docs/firestorehttps://firebase.google.com/docs/firestore/query-data/get-data
- [8]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_.md#adddoc
- [9]firebase.google.com/docs/firestorehttps://firebase.google.com/docs/firestore/manage-data/add-data
- [10]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_.md#setdoc
- [11]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_.md#updatedoc
- [12]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_.md#deletedoc
- [13]firebase.google.com/docs/firestorehttps://firebase.google.com/docs/firestore/manage-data/delete-data
- [14]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth#sendpasswordresetemail
- [15]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/manage-users#send_a_password_reset_email
- [16]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth#sendemailverification
- [17]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/manage-users#send_a_user_a_verification_email
- [18]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth#deleteuser
- [19]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/manage-users#delete_a_user
- [20]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth#signout
- [21]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth#getidtoken
- [22]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth#updateemail
- [23]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/manage-users#update_a_users_email
- [24]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth#updatepassword
- [25]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/manage-users#update_a_users_password
- [26]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth#confirmpasswordreset
- [27]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_#getdoc
- [28]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_#runtransaction
- [29]firebase.google.com/docs/firestorehttps://firebase.google.com/docs/firestore/manage-data/transactions
- [30]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/storage#uploadbytes
- [31]firebase.google.com/docs/storagehttps://firebase.google.com/docs/storage/web/upload-files
- [32]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/storage#getdownloadurl
- [33]firebase.google.com/docs/storagehttps://firebase.google.com/docs/storage/web/download-files
- [34]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/email-link-auth
- [35]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#signinwithemaillink
- [36]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/anonymous-auth
- [37]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#signinanonymously
- [38]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#updateprofile
- [39]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/manage-users#update_a_users_profile
- [40]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#linkwithcredential
- [41]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/account-linking
- [42]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#reauthenticatewithcredential
- [43]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/manage-users#re-authenticate_a_user
- [44]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/auth.md#verifybeforeupdateemail
- [45]firebase.google.com/docs/authhttps://firebase.google.com/docs/auth/web/manage-users#set_a_users_email_address
- [46]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_.writebatch#writebatchcommit
- [47]firebase.google.com/docs/firestorehttps://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes
- [48]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/firestore_.md#getcountfromserver
- [49]firebase.google.com/docs/firestorehttps://firebase.google.com/docs/firestore/query-data/aggregation-queries
- [50]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/storage.md#deleteobject
- [51]firebase.google.com/docs/storagehttps://firebase.google.com/docs/storage/web/delete-files
- [52]firebase.google.com/docs/functionshttps://firebase.google.com/docs/functions/callable?gen=2nd
- [53]firebase.google.com/docs/referencehttps://firebase.google.com/docs/reference/js/functions.md#httpscallable
Need a different package?
Request a profile