Skip to content

cannot handle error from useFirestoreCollectionData #540

Closed

Description

@perryd01

Version info

React: 18.2.0

Firebase: 9.9.0

ReactFire: 4.2.2

Other (e.g. Node, browser, operating system) (if applicable):
Next.js 12.2.2

Test case

use useFirestoreCollectionData and handle FirebaseError: Missing or insufficient permissions.

Steps to reproduce

  • Set permissions in firebase console and set a rule that doesn't allow the query for a user
  • Make the query
const { status, data: users, error } = useFirestoreCollectionData(usersQuery);

Expected behavior

The hook doesn't throw and the error is in error variable

Actual behavior

The hook throws and error cannot be handled without try catch (that should't be used?)

React.useEffect(() => {
const subscription = observable.subscribe({
next: () => {
dispatch('value');
},
error: (e) => {
dispatch('error');
throw e;
},
complete: () => {
dispatch('complete');
},
});
return () => subscription.unsubscribe();
}, [observable]);

Activity

  1. aadito123 commented on Sep 6, 2022

    @aadito123

    I have a similar issue with useFirestoreDocData and useFirestoreDocDataOnce.

    The error actually originates from the SuspenseSubject class which throws an error when the value property is read while the Subject has an error i.e. Firebase Permission Error.

    This error is also cannot be caught without a React Error Boundary. I think it would be better to pass in a flag like throwErrorInObservable that allows it to return the initialValue or just undefined to represent the error state. Would be more convenient to check for errors synchronously using the error attribute in the ObservableStatus. I would not mind making a PR for this if maintainers can sign off on it.

    get value(): T {
    // TODO figure out how to reset the cache here, if I _reset() here before throwing
    // it doesn't seem to work.
    // As it is now, this will burn the cache entry until the timeout fires.
    if (this._error) {
    throw this._error;
    } else if (!this.hasValue) {
    throw Error('Can only get value if SuspenseSubject has a value');
    }
    return this._value as T;
    }

    Another approach could be to not set hasValue as true when there is an error however it seems that there might be a lot of code already dependent on such behaviour.

  2. aadito123 commented on Sep 13, 2022

    @aadito123

    tagging @jhuleatt to hopefully increase visibility

  3. jaskaye17 commented on Dec 3, 2022

    @jaskaye17

    Bumping this as well. Crashing on FirebaseError: Missing or insufficient permissions renders this library unusable for me as this is a valid use case which I am unable to handle.

  4. utkudotdev commented on Dec 4, 2022

    @utkudotdev

    Same here. Anyone have something on this?

  5. beamercola commented on Dec 20, 2022

    @beamercola

    same

  6. jbaldassari commented on Jan 5, 2023

    @jbaldassari

    useFirestoreDoc also has this issue.

  7. IAmJamesMudge commented on Feb 23, 2024

    @IAmJamesMudge

    Bump. I can't use this library either because of this issue. Wrapping the entire function body in a try/catch does allow you to catch the error but is not tenable.

  8. rangel-rangelov commented on Apr 3, 2024

    @rangel-rangelov

    Bump, same here.

  9. samdeen commented on May 21, 2024

    @samdeen

    Bump, when will this be fixed?

  10. added
    v5Planned for v5
    and removed
    v5Planned for v5
    on Jul 14, 2026
  11. added a commit that references this issue on Jul 15, 2026
    b113bc3
  12. added a commit that references this issue on Jul 27, 2026
    0b70a12
  13. tyler-reitz commented on Jul 27, 2026

    @tyler-reitz
    Contributor

    Fixed by #735, merged into the v5 branch.

    The unconditional throw you linked at useObservable.ts#L120-L134 is exactly what changed. In non-suspense mode (the default) errors are no longer thrown; they are surfaced via status with the error on error, which is the behavior you asked for:

    const { status, data: users, error } = useFirestoreCollectionData(usersQuery);
    if (status === 'error') {
      // error is the FirebaseError, e.g. "Missing or insufficient permissions."
    }

    No try/catch needed. Previously status: 'error' was unreachable in practice because the throw happened first.

    In suspense mode (suspense: true) errors are still thrown so an Error Boundary can catch them. That is intentional and unchanged.

    Please note this ships in 5.0.0, not in any 4.x release, since the change is breaking for anyone currently relying on an Error Boundary in non-suspense mode. See the v4 to v5 upgrade guide for the migration path.

  14. locked and limited conversation to collaborators on Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions