angularfire icon indicating copy to clipboard operation
angularfire copied to clipboard

AddDoc error not being caught

Open manuelsrleon opened this issue 1 year ago • 2 comments

Good morning.

In our project, I've been trying to handle the output of an addDoc call using angular/fire. The exception will get caught but not the error thrown by addDoc. When uncommenting the line //throw "patata" the catch block will get executed.

async saveProjectTest(projectTracking: ProjectTracking) {
    const projectTrackingsRef = collection(this.firestore, 'projecttrackings');
    try{
      console.log("here1");
      //throw "patata";
      await addDoc(projectTrackingsRef, projectTracking);    
      console.log("here2");
    }catch(error){
      console.log("caught");
    };
  }

I don't know if it is a bug or what it is, but this is specially important since it seems like the appropriate way to handle connection errors and any other kinds of errors in my app. Right now I can only implement the "happy path".

I'm using Chromium v130, angularfire 18.0.1, with Angular 18.1.3, connecting to a docker container running a firebase emulator. When I want to test no connectivity, I take down the firebase container.

Thanks in advance, appreciate your help.

manuelsrleon avatar Dec 16 '24 12:12 manuelsrleon

This issue does not seem to follow the issue template. Make sure you provide all the required information.

google-oss-bot avatar Dec 16 '24 12:12 google-oss-bot

Hi @manuelsrleon, the behavior you’re observing is not a bug but rather a consequence of Firestore/AngularFire’s offline-first design.

Details • Local Write vs. Server Sync: When you call addDoc, the document is immediately written to the local cache and the Promise resolves as soon as that write succeeds—regardless of whether the change has been synchronized with the server. This means that even if the Firebase emulator (or server) is down, addDoc will resolve because the local write was successful. • Error Handling: Since the write to the local cache succeeds, no error is thrown, and thus the catch block is not executed. An error would only be caught if you explicitly throw one (as in throw "error"), or if you disable offline persistence so that the write waits for server confirmation.

Approaches to Handle Connectivity or Synchronization Issues

  1. Monitor Sync Status via Snapshots: You can use onSnapshot to check for pending writes. For example:
import { onSnapshot } from '@angular/fire/firestore';

const unsubscribe = onSnapshot(docRef, (doc) => {
  if (doc.metadata.hasPendingWrites) {
    console.log("Local changes are pending synchronization.");
  } else {
    console.log("Changes have been synchronized with the server.");
  }
}, (error) => {
  console.error("Snapshot error:", error);
});
  1. Disable Offline Persistence: Disabling offline persistence forces the write to wait for server confirmation, allowing you to catch connectivity errors immediately. However, this approach sacrifices offline functionality:
import { initializeFirestore, disableNetwork } from '@angular/fire/firestore';

const firestore = initializeFirestore(app, {
  experimentalForceLongPolling: true, // Optional: depending on your environment
});

disableNetwork(firestore).catch((error) => {
  console.error("Error disabling network:", error);
});
  1. Implement Custom Error Handling: Since Firestore will continue retrying failed writes in the background, you might need to implement custom logic. For example, you could: • Monitor pending writes over a period of time. • Use a Cloud Function or another background process to verify that writes are eventually synchronized. • Notify the user if the document hasn’t been confirmed after a certain period.

Summary

The addDoc operation resolves its Promise once the document is written locally. It does not wait for server synchronization, so connectivity errors won’t trigger the catch block. To handle such errors, consider monitoring the synchronization status or disabling offline persistence based on your application’s needs.

danilipari avatar Feb 10 '25 01:02 danilipari