Firebase Functions: Error: Client is offline - node.js

I just recently started using Firebase functions for the first time. When I was using Firebase Functions for Firestore, it worked fine but after I switched to Realtime, I've consistently been getting "Error: Client is offline".
It happens when I turn on node.js and run my application for the first time, and I .get() some data from the realtime database.
When I click on the respective line at which the error exists, it shows me this.
This is how I initialized firebase-admin:
admin.initializeApp({
projectId: <project id>,
storageBucket: <bucket url>,
credential: admin.credential.cert(serviceAccount),
databaseURL: <db url>,
});
Is it because I have the FIREBASE_CONFIG and GCLOUD PROJECT environment variables are missing error? I've seen a lot of different posts that other people are getting the same issue, but I haven't come across a proper solution.
If anyone has any solutions or if you need more information, please let me know!

I have a feeling you may be hitting a race condition in the JavaScript implementation of get(). If that is the case, you can work around it by using the once() method, which should work exactly the same in this scenario:
const _dataSnapshot = await admin.database().ref('users').child(req.body.user_uid).once();
...

Related

Firebase - Error: 16 UNAUTHENTICATED: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid au

Hello I'm using firebase functions and I have created a Node.js project with firebase init, then I selected the options functions, firebase and storage. The project works with the firebase-admin NPM package.
When I deploy the project with firebase deploy everything goes well, but when I run the function on the cloud, it says the following message:
I have tested the entire project with the emulators and it works well.
Project Structure:
What is causing this error? Thanks!
I solved it. The problem was that I had this in the initializeApp:
const serviceAccount = require("../project-name-f3ad6ae0572f.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: BUCKET_NAME,
});
This is incorrect because I was missing the firebase configuration that is given on the Firebase Console -> Project Settings -> Your Apps.
Then, the result has to be like this:
const firebaseConfig = {
apiKey: "xxx-your-api-key-xxx",
authDomain: "project-name.firebaseapp.com",
projectId: "project-name",
storageBucket: "project-name.appspot.com",
messagingSenderId: "xxxxxxxxxxxxxxxx",
appId: "x:xxxxxxxxxxxxxxx:web:xxxxxxxxxxxxxxx",
measurementId: "G-XXXXXXXXX",
};
admin.initializeApp(firebaseConfig);
verify your pc time, i had same problem and resolving when update pc time.
import * as admin from 'firebase-admin';
const serviceAccount = require('./firebase.json');
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
}
export const firebaseDB = admin.firestore();
I might be late to this question but I faced a similar issue yesterday (16 October 2022). What I figured is that, when you set your computer's time manually, firebase doesn't work.
So your firebase timestamp rules must match with your current host time.
The code for the function framework is actually public in the GoogleCloudPlatform/functions-framework-nodejs repository (although not advertised anywhere).
In particular you can see there the cases where killInstance is used, which is the one triggering exit code 16:
const killInstance = process.exit.bind(process, 16);
These cases are (at the time of writing):
· uncaughtException
· unhandledRejection
I had the same issue today, if it's only happening in your local environment, there's a 99% chance that your computer's time is wrong.

cloud base functions accessing project firestore from emulator

I have a firebase project which has a project id and data in firestore. The app works great on the web, android studio, actual device etc to connect to my project firestore documents.
I want to create a cloud function so installed the firebase CLI, created a function but when i want to read data it will only access collections created at http://localhost:4000/firestore.
I have tried creating a serviceAcount from my firebase console.
const admin = require('firebase-admin');
var serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
I have tried using my known working firebaseConfig:
const admin = require('firebase-admin');
firebaseConfig = {
apiKey: "***************",
authDomain: "**********.firebaseapp.com",
projectId: "**********-****",
storageBucket: "*******-******.appspot.com",
messagingSenderId: "********",
appId: "1:***********:web:*************"
};
admin.initializeApp(firebaseConfig);
I have read everything (probably not) out there over the last couple days. It took me forever to even understand why the db.collection request was not returning anything, before i realized it was looking in another firestore bucket at http://localhost:4000/firestore (i created a document, and the cloud function immediately returned a working result). I thought I had figured it out.
How do i point the emulator to my existing firestore project data. I am clearly missing something really basic in understanding.
After debugging and thinking about it I realized there had to be something very basic:
firebase emulators:start --only functions
When i started the emulator with --only functions it gave me a warning that production data would be used and as thick as I am the penny dropped.
Make sure to specify --only functions which precludes the emulated firestore on localhost:4000.
It was probably so obvious no one anywhere actually stated it or what happens if you omit --only functions.

Node Lambda timing out firebase-admin SDK

I'm trying to send push notifications through Firebase Cloud Messaging from a node js lambda in AWS.
My function works and I receive the notification on my phone, however the lambda keeps timing out (even at 20s timeout). I can see in logs my lambda callback is being called. It appears that something is preventing the lambda from returning.
I initialise with:
const serviceAccount = require('./firebaseKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'xxx',
});
and send with:
const fcmResponse = await admin.messaging().sendToDevice(fcmToken, message);
My hunch is that it's something here preventing it from returning as everything else is pretty vanilla.
Does anyone have any ideas as to what's causing the timeouts?
For others looking at this.
Firebase seems to leave some stuff kicking around, which means the callback is never called.
Adding the following line in the handler solves the problem:
context.callbackWaitsForEmptyEventLoop = false;

Deploying firebase cloud function fails when I initialise firebase with a service account key

so very recently I started using google's firebase cloud functions, and loved it immediately! I very quickly restructured a project I was going to work on, and included firebase in it, so I could use the cool features of firestore, in combination with cloud functions.
Up until today, everything went on smoothly; pretty much, until I decided to play with google's FCM (Firebase Cloud Messaging) to send notifications via node js. Before this, I had created some really dense functions and already deployed to my console which were working seamlessly.
The tricky part is, at the time I created and deployed these functions, I initialised my firebase app in node js with admin.initalizeApp().
With this, everything worked fine(both locally & deployed) until I tried to use admin.messaging().sendToDevice... which resulted in a very nasty error, that basically told me I couldnt send notifications if I wasnt authenticated..
The error
(Error: An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions. See https://firebase.google.com/docs/admin/setup for setup instructions. Raw server response: "<HTML>
> <HEAD>
> <TITLE>Unauthorized</TITLE>
> </HEAD>
> <BODY BGCOLOR="#FFFFFF" TEXT="#000000">
> <H1>Unauthorized</H1>
> <H2>Error 401</H2>
> </BODY>
> </HTML>
> ". Status code: 401.)
Following the error, I used a few tips from some other users on stack overflow who had faced this error, and most of them suggested that I download a service key from my console, and initialise my firebase app with admin.initializeApp({credential:admin.credential.cert(serviceAccount)})
This solution worked beautifully, as it allowed me to test my notification without seeing the above error ever again.
However, when all my tests were done, and I was ready to deploy, the new function I had just created to work on notification, as well as all my previously deployed functions could not get deployed. All of a sudden, the old working functions in my console had a red exclamation mark beside them, and I had to get rid of them. Even after I cleared out all of my console and tried to redeploy all my functions, it failed, and failed and failed with no errors(context: I wasted the whole day!!! lool!) Every tip on the internet failed for me, until I reverted back to my old way of initialising my firebase app admin.initializeApp(), then booom! all my functions uploaded successfully, and then again, the authentication error appeared again when I tried to retest my notification function.....
I guess my question is: is there anything I don't know about deploying functions to the firebase console with my app initialised with a service account key I downloaded from my console?
Is there something else I need to do to get my functions to deploy properly every time I init my firebase admin app with a service account key?? Because initialising the app with just .initalizeApp() works fine for all other purposes both locally and when deployed, except when using FCM. Can anyone please help with what is happening here??
I think it can be solved by initializing two apps and using them as objects described here. One with credentials that work for other functions and one for messaging.
If you need it only for one function you can do it even inside it. I have tested it like this:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
exports.first_app = functions.https.onRequest(async (req, res) => {
res.json(admin.app().name);
})
exports.other_app = functions.https.onRequest(async (req, res) => {
var otherApp = admin.initializeApp({
credential: **<< different credential here >>**
}, "2nd_app");
res.json(otherApp.name);
})
as already mentioned, you should initialize a second app just for the new function you are creating. You should put the initialization code inside the new function like this
export const saveMap = functions.https.onRequest(async (req, response) => {
const serviceAccount = require("./../serviceAccountKey.json");
admin.initializeApp({
projectId: "serviceAccount.project_id",
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your_project_id_here.firebaseio.com", //update this
storageBucket: "your_bucket_name_here.appspot.com" //update this
}, "2nd_app")
I had the same issue and once I put the second initialization code into the new function, it worked. Note that in this code the serviceAccountKey.json is in the same folder as src and lib.

No longer captures the event from firebase by Admin SDK

I have installed and run firebase admin on my node server, it has been running well until today, there is no given error to tell what happened, it simply stops working.
var admin = require("firebase-admin");
var serviceAccount = require("mycom-firebase-adminsdk-d1ebt123456.json");
var app = FireBaseAdapter.admin.initializeApp({
credential: FireBaseAdapter.admin.credential.cert(serviceAccount),
databaseURL: "https://xxxx.firebaseio.com"
});
var db = app.database();
var ref = db.ref("messages"); // this node actually exists in my db.
ref.on("value", function(snapshot) {
// this will never be called - which has been working before.
console.log(snapshot.val());
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
I even wrap it in the try catch to print out the error, but there isn't any. I can log into the firebase console in the account and see my database with no change (small database) (although it seems be slower than normal).
Is there something wrong with firebase Admin SDK? Any help is appreciated.
After spending many hours to find out the cause, I found the problem.
Since I couldn't find any way to enable log of firebase-admin, so it was the dead end to troubleshoot the issue while everything runs silently, so I switched to use the firebase package to have the logging
var firebase = require("firebase");
firebase.initializeApp({
databaseURL: "https://xxxxx.firebaseio.com",
serviceAccount: '....'
});
firebase.database.enableLogging(true); // <=== important
My issue is quite similar to this question
then I could see the actual error:
p:0: Failed to get token: Error: Error refreshing access token:
invalid_grant (Invalid JWT: Token must be a short-lived token and in a
reasonable timeframe)
The solution for this issue was explained on this anwser. This issue caused by a poor synchronisation of the computer's clock where the code was executed that had a lag of 5 minutes (due to a faulty battery for the internal clock).
It started working again when I manually changed the internal time of my computer to the correct one (or totally I reset my computer date-time).
In my case, after resetting the datetime&timezone, the firebase automatically works again and I do not need to re-generate another service account.

Resources