Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Firestore] What is the recommended way to check for an instance of a Firestore error using this package? #2257

Open
jketcham opened this issue Jul 19, 2023 · 11 comments
Assignees

Comments

@jketcham
Copy link

jketcham commented Jul 19, 2023

Using firebase-admin, what is the recommended way to verify an error is Firestore related? And so that typescript knows that the error instance will have the code property, etc?

Ideally, I'd be able to verify the error is an instance of FirestoreError, but the error I'm experiencing now seems to be grpc related, as the code property is returning a number corresponding to the errors here.

There are several issues in this repository around getting access to error classes, with no clear answers.

If I'm missing something, please point me in the right direction.

@google-oss-bot
Copy link

I found a few problems with this issue:

  • I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
  • This issue does not seem to follow the issue template. Make sure you provide all the required information.

@ehsannas
Copy link

Thanks for reporting @jketcham . I'll take a look.

@jketcham
Copy link
Author

Thanks @ehsannas, I appreciate it!

@ehsannas
Copy link

@jketcham I'm wondering what package is you're using.
the Admin Node package doesn't seem to throw any FirestoreErrors. It does throw Errors.

Based on the link you provided, you're probably using the Node.js client, which does define and use FirestoreErrors.

Firestore has several dependencies (e.g. grpc), and it'd be unwise to catch all potential exceptions thrown from dependencies and re-wrap them into a FirestoreError.

@jketcham
Copy link
Author

jketcham commented Aug 1, 2023

@ehsannas I'm using the firebase-admin package in these instances, and so my question here was to see what package I could import some class of an Error from to use in my error handling code to check for specific firestore related error codes. Or if there was some other recommended way to handle firestore-specific errors from firebase-admin.

I think I'm a little confused between the different available packages, specifically, firebase-admin, @google-cloud/firestore and firebase (which includes @firebase/firestore).

Ideally, I would be able to import and check for instances of FirestoreError as you pointed out exists here, but it looks like that isn't exported from firebase-admin or @google-cloud/firestore, only @firebase/firestore included in the firebase package.

So for example I'd like to do something like this:

import { FirestoreError } from "@google-cloud/firestore"; // <--- Or whatever package
import { db } from "./my-firebase-admin-module";

try {
  await db.collection("col_id").doc("doc_id").create({ ... });
} catch (error) {
  if (error instanceof FirestoreError) {
    if (error.code === "already-exists") { // <--- Typescript would pick up on FirestoreErrorCode
      // ...do something specific in this case...
      return;
    }
  }
  // If something unexpected, re-throw
  throw error;
}

What I've seen is when using firebase-admin, I'll get a plain Error back which does have a code property that corresponds to the underlying grpc errors.

@tiagoboeing
Copy link

I have the same issue; the only way to work around this it's using the @firebase/util package and importing FirebaseError from it as I saw in other discussions, but this doesn't catch all errors. I'm working with Cloud Messaging and some exceptions are not handled when using instance of.

Would be a nice fix correct export error interfaces to be imported on the projects.

Using:

import { FirebaseError } from 'firebase-admin/lib/utils/error';

Can't use the class because is not exported: Error: Package subpath './lib/utils/error' is not defined by "exports"...


import { FirebaseError } from 'firebase-admin';

Is an interface and can't use with instance of to compare error types.

@IchordeDionysos
Copy link
Contributor

To be clear the PR I was opening is mostly for FirebaseAuth where handling different error codes is essential and with the current approach you have to write weird and ugly Typescript type guards to make sure it's indeed a Firebase Auth error.

if ('code' in error && typeof error.code === 'string') {
 ...
}

instead of just

if (error instanceof FirebaseAuthError) {
    if (error.code === "already-exists") { // <--- Typescript would pick up on FirebaseAuthErrorCode
      // ...do something specific in this case...
      return;
    }
  }

@ablbol
Copy link

ablbol commented Jan 1, 2024

hi @jketcham, where you able to resolve this issue? I have the exact same problem. I have a cloud function and would like to do something like this in my function but don't know how to import FirestoreException:

    import * as admin from 'firebase-admin';
    const db = admin.firestore();

    try {
      // if the document is not found, this will throw an exception
      // what is the exception type and how do I read the code 
      await db.doc(`/users/${uid}`).update({
        member,
      });
    } catch (error) {
      if (error instanceof FirestoreException)  { // <==== how do I import this exception??
        if (error.code === 5) { // <=== which API should I use for document not found
           // what should I do over here
        }
      }
    }

@dogemad
Copy link

dogemad commented Apr 12, 2024

This is the same for all namespaces in firebase-admin. The convenience for users to handle errors is too low.
It is not possible to determine whether the error raised is a FirebaseError instance. (Not only FirebaseError but also runtime-level Error exists, so instance checking is necessary.)
The simplest approach is for the library to at least provide a dictionary of comparable error codes.

@Miodec
Copy link

Miodec commented Sep 13, 2024

(Speaking from the perspective of auth errors here, as dogemd said this is the case everywhere though)

Any update on this? Currently error handing is really awkward. In Typescript all catch blocks give any type, so the standard way of handling errors is:

} catch(error) {
  if (error instanceof Error){
    console.log(error.message) // proper types for message here
  }
}

Because firebase-admin doesn't export whats being thrown, this is impossible. It does export FirebaseError but thats a child of whats thrown:

{
  codePrefix: string,
  errorInfo: FirebaseError
}

(also IMO, "errorInfo" storing a FirebaseError is quite confusing)

I found a hack but its quite ugly:

type FirebaseErrorParent = {
  errorInfo: FirebaseError;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isFirebaseError(err: any): err is FirebaseErrorParent {
  return (
    typeof err === "object" &&
    "errorInfo" in err &&
    "codePrefix" in err &&
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    typeof err.errorInfo === "object" &&
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    "code" in err.errorInfo &&
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    "message" in err.errorInfo
  );
}
} catch (err) {
    if (isFirebaseError(err) && err.errorInfo.code !== "auth/user-not-found") { //here we have proper types now
      //
    }
  }

Without this you need to do some weird typecasting, or ignoring the eslint rule which is also not ideal.

(also it would be nice if FirebaseError.code would be a union of the possible codes, not a string - that way we can get auto completion)

@bGuirra
Copy link

bGuirra commented Oct 30, 2024

This is so weird because it makes almost impossible to write an unit test targeting some behavior regard Firebase errors, I'm aware of the "hacks" around it, but it makes no sense to me. It's easier to not even check for instances of Firebase errors in first place. They should expose a better interface for constructing the errors in order to make it easier to create an instance in tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants