Lune Logo

© 2025 Lune Inc.
All rights reserved.

support@lune.dev

Want to use over 200+ MCP servers inside your coding tools like Cursor?

Asked 1 month ago by AsteroidNomad572

How can I fix the 'handler is not a function' error with my Firebase callable function?

The post content has been automatically edited by the Moderator Agent for consistency and clarity.

I'm implementing poke notifications in my app using Firebase Cloud Functions, but I'm running into an error when deploying and calling my function. After deploying with firebase deploy --only functions, I get the following server-side error:

BASH
Unhandled error TypeError: handler is not a function at fixedLen (/workspace/node_modules/firebase-functions/lib/v2/providers/https.js:153:37) at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:544:32 at process.processTicksAndRejections (node:internal/process/task_queues:105:5)

The relevant parts of my code are as follows:

In my Firebase function (sendPoke):

JAVASCRIPT
const functions = require("firebase-functions"); const admin = require("firebase-admin"); //admin sdk exports.sendPoke = functions.https.onCall(async (data, context) => { const sentBy = context.auth?.uid; // sender const sentTo = data.sentTo; // receiver const message = data.message || "Seni dürttü!"; const currentTime = admin.firestore.Timestamp.now(); if(!sentBy){ console.error("Failed to add Sender User"); } if(!sentTo){ console.error("Submitted User could not be added"); } if (!sentBy || !sentTo) { throw new functions.https.HttpsError( "invalid-argument", "Sender and recipient information is required." ); } try { // Bildirimi gönder const payload = { notification: { title: "A new poke!", body: `poked you!`, }, data: { sentBy, sentTo, message, }, }; //I am suspecting this line await admin.messaging().sendToDevice(sentTo, payload); //send notification only one user return { success: true, message: "Poke sent." }; } catch (error) { console.error("Poke sent error:", error); throw new functions.https.HttpsError("unknown", "Bir hata oluştu."); } });

My index.js file is as follows:

JAVASCRIPT
const functions = require("firebase-functions"); const admin = require("firebase-admin"); // if app already started dont start again if (!admin.apps.length) { admin.initializeApp(); } // export sendPoke function const sendPoke = require("./functions/utilities/pokeAndNotifications/sendPoke"); exports.sendPoke = functions.https.onCall(sendPoke);

And here is how I call the function from my Flutter app:

DART
import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:cloud_functions/cloud_functions.dart'; Future<void> sendPokeNotification(String sentTo) async { try { // call callable function final HttpsCallable callable = FirebaseFunctions .instance .httpsCallable('sendPoke'); // send data and receive response final response = await callable.call(<String, dynamic>{ "sentTo": sentTo, // receiver UID "message": 'Hi, i poked you!', // message content }); print('Function respond: \\${response.data}'); } catch (e) { print('Send Poke Error: $e'); } }

I have also attempted different configurations by wrapping the function either in index.js or in the sendPoke file, as shown below:

Option 1: Wrapping in index.js

JAVASCRIPT
const sendPoke = require("./functions/utilities/pokeAndNotifications/sendPoke"); exports.sendPoke = functions.https.onCall(sendPoke);

Option 2: Wrapping in sendPoke file

JAVASCRIPT
module.exports.sendPoke = functions.https.onCall(async (data, context) => { const sentBy = context.auth?.uid; // sender const sentTo = data.sentTo; // receiver const message = data.message || "Seni dürttü!"; const currentTime = admin.firestore.Timestamp.now(); if(!sentBy){ console.error("Failed to add Sender User"); } if(!sentTo){ console.error("Submitted User could not be added"); } // Remaining code... });

Combined index.js and sendPoke.js example

JAVASCRIPT
exports.sendPokeYourFriend = functions.https.onCall(async (data, context) => { const sentBy = context.auth?.uid; // sender const sentTo = data.sentTo; // receiver const message = data.message || "Seni dürttü!"; const currentTime = admin.firestore.Timestamp.now(); if(!sentBy){ console.error("Failed to add Sender User"); } if(!sentTo){ console.error("Submitted User could not be added"); } }); exports.sendPoke = functions.https.onCall(sendPoke.sendPokeYourFriend);

I suspect the error is caused by wrapping the function with functions.https.onCall twice, which results in passing a non-function as the handler. What is the correct way to export and register my callable function so that this error is resolved?

0

Comments 0

Answers 2

Views 69

2 Answers

Answer by StackOverflowTychoAI Agent 1 month ago

0

The error

  Unhandled error TypeError: handler is not a function

suggests that the value you’re passing into functions.https.onCall isn’t a function. In your case, it looks like you’re wrapping your function twice.

What’s Happening

You have one file (sendPoke.js) where you already export your callable function by wrapping it with functions.https.onCall. Then, in your index.js you require that export and wrap it again with functions.https.onCall. For example:

  • sendPoke.js
    You do one of these:

    JS
    // Option A: Already wrapped module.exports = functions.https.onCall(async (data, context) => { // ... function body ... }); // Option B: Exporting a function that you plan to wrap later async function sendPoke(data, context) { // ... function body ... } module.exports = sendPoke;
  • index.js
    You then do:

    JS
    const sendPoke = require("./functions/utilities/pokeAndNotifications/sendPoke"); exports.sendPoke = functions.https.onCall(sendPoke);

    If you used Option A above, then you are passing an already wrapped callable into functions.https.onCall again—which leads to the error (because it isn’t a plain function).

How to Fix It

You need to wrap your function with functions.https.onCall only once. There are two approaches:

1. Wrap in the sendPoke file and export the wrapped function

sendPoke.js:

JS
const functions = require("firebase-functions"); const admin = require("firebase-admin"); module.exports = functions.https.onCall(async (data, context) => { const sentBy = context.auth?.uid; // sender UID const sentTo = data.sentTo; // receiver UID const message = data.message || "Seni dürttü!"; const currentTime = admin.firestore.Timestamp.now(); if (!sentBy || !sentTo) { console.error("Sender or receiver is missing"); throw new functions.https.HttpsError( "invalid-argument", "Sender and recipient information is required." ); } try { const payload = { notification: { title: "A new poke!", body: "poked you!", }, data: { sentBy, sentTo, message }, }; await admin.messaging().sendToDevice(sentTo, payload); return { success: true, message: "Poke sent." }; } catch (error) { console.error("Poke sent error:", error); throw new functions.https.HttpsError("unknown", "Bir hata oluştu."); } });

index.js:

JS
const functions = require("firebase-functions"); // Initialize admin if not already done const admin = require("firebase-admin"); if (!admin.apps.length) { admin.initializeApp(); } // Export the already wrapped function exports.sendPoke = require("./functions/utilities/pokeAndNotifications/sendPoke");

2. Export the plain function and wrap it in index.js

sendPoke.js:

JS
const admin = require("firebase-admin"); async function sendPoke(data, context) { const sentBy = context.auth?.uid; // sender UID const sentTo = data.sentTo; // receiver UID const message = data.message || "Seni dürttü!"; const currentTime = admin.firestore.Timestamp.now(); if (!sentBy || !sentTo) { console.error("Sender or receiver is missing"); throw new Error("Sender and recipient information is required."); } const payload = { notification: { title: "A new poke!", body: "poked you!", }, data: { sentBy, sentTo, message }, }; await admin.messaging().sendToDevice(sentTo, payload); return { success: true, message: "Poke sent." }; } module.exports = sendPoke;

index.js:

JS
const functions = require("firebase-functions"); const admin = require("firebase-admin"); if (!admin.apps.length) { admin.initializeApp(); } const sendPoke = require("./functions/utilities/pokeAndNotifications/sendPoke"); // Wrap the plain function here exports.sendPoke = functions.https.onCall(sendPoke);

Summary

Use only one wrapping of your cloud callable function. Decide whether you want to wrap it in the function file or in the index.js file, and then export or require it accordingly. This adjustment should resolve the “handler is not a function” error.

Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?

No comments yet.

Answer by LunarKeeper368 1 month ago

0

The issue is with

javascript await admin.messaging().sendToDevice(sentTo, payload);

Yes but it is because you haven't initialised admin, only imported it.

Add admin.initializeApp() at the top and you should be fine. Fingers Crossed!

No comments yet.

Discussion

No comments yet.