Problem
I was working with a team on an industry applied project for a client in Ottawa, where we built a simple delivery React Native app using Firebase. As I was tasked with debugging an issue related to notifications, our team encountered a deployment error when trying to implement a document trigger Cloud Function.
We were implementing a notification feature, where users receive notifications about the delivery status, but the deployment error prevented us from achieving this functionality.
Error: Request to https://firestore.googleapis.com/v1/projects/xxx-****/databases/(default) had HTTP Error: 404 Project 'xxx' or database '(default)' does not exist.
Surprisingly, other Firebase operations worked correctly:
- Reading/writing to Firestore from the app
- Deploying Cloud Functions without document triggers
Investigation
I discovered that our team had assigned a custom database name custom-db-name
to the Firestore instance during project initialization. Our app code was indeed passing this custom-db-name
to the Firebase Runtime SDK when performing reading and writing operations to Firestore. This explained why other Firebase operations like reading/writing to Firestore from the app and deploying Cloud Functions without document triggers were working correctly.
const db = getFirestore(app, "custom-db-name");
However, I suspected that the issue lay in how the document trigger Cloud Function was being configured. To better understand the problem, I examined the Firebase SDK source code and found the onDocumentUpdated
function interface, which revealed an optional parameter for the database name (database). This made sense, as our team had already defined a custom DB name.
interface DocumentOptions {
document: string;
database?: string; // Optional parameter for database name
}
I instantly passed the custom-db-name
into the trigger setup. This has resolved the deployment issue.
// Before (failing):
exports.notifyOnDeliveryUpdate = functions.firestore
.document("movers/{moverId}")
.onUpdate((change, context) => {
// Notification logic
});
// After (working):
exports.notifyOnDeliveryUpdate = functions.firestore.onDocumentUpdated(
{
document: "movers/{moverId}",
database: "custom-db-name", // Added database parameter
},
(event) => {
// Notification logic
}
);
However, I don't like black boxes. I needed to know why Firebase was acting like this. So, I chose to study Firebase architecture to get a clear view of how trigger setup and function run link up.
Root Cause
After digging deeper, I realized that this was Google's implementation of Publish/Subscribe (Pub/Sub) model (aka EVENTARC), a decoupled design where events are published by Firestore and subscribed to by Cloud Functions.
Specifically, Firebase uses separate systems for runtime operations (reading/writing data) and trigger registration (watching for events). The trigger system (Eventarc) configures watchers at deploy time, not runtime. This means that specifying a custom database in our app code only affects runtime operations, while the trigger deployment process looks for a default database that doesn't exist in our project.
In other words, the trigger system and the runtime SDK are two separate components. One sets off the alarm, the other decides what to do after it's been tripped.
The Firebase folks chose to keep "(default)" as the basic database name to work with old projects that use that setup. But, when our project used a different database, it wasn't propagated to the trigger system leading to the 404 error.
Key Takeaways
Firebase architecture separates concerns between runtime operations and trigger registration.
This separation enables benefits such as:
- Independent scaling of event watching and function execution
- Support for multiple databases with the same function code
- Early event filtering for improved performance
Best practices include:
- Documenting all non default configurations during project setup
- Specifying database names in both runtime code and trigger configurations
- Considering deploy time vs. runtime behaviors when troubleshooting cloud services