Firebase Function Not Found (2026)

Calling a function returns "not found." Likely region, name, or deploy.

You deployed a Firebase Cloud Function. From the frontend:

const result = await httpsCallable(functions, 'sendEmail')({to: 'x'});

You get:

FirebaseError: Function not found: sendEmail

Or a direct HTTP fetch returns:

404 Not Found

But the Firebase Console clearly lists sendEmail under Functions. Welcome to the most confusing Cloud Functions error — “visible in console” ≠ “callable from client.” The problem is always one of: name / region / deploy state.

Common causes

Ordered by hit rate, highest first.

1. Region mismatch between client and function

Most common. Function declares region: 'asia-east1', but the client SDK doesn’t specify a region and defaults to us-central1 — function isn’t there.

How to spot it:

  • Function code: onCall({ region: 'asia-east1' }, ...) or v1: functions.region('asia-east1').https.onCall(...)
  • Client: getFunctions(app) with no region = us-central1
  • Mismatch = not found

2. Function name typo / case mismatch

// function code
export const sendEmail = onCall(...);

// client
httpsCallable(functions, 'send-email')  // ❌ kebab-case
httpsCallable(functions, 'sendmail')    // ❌ typo

Firebase function names are export variable names — case-sensitive exact match.

How to spot it: firebase functions:list or copy exact name from console; compare with client.

3. Build silently failed during deploy

CLI says Deploy complete!, but one function got skipped due to a TS error or missing dep. Others succeeded; this one silently didn’t.

How to spot it: firebase deploy --only functions --debug and search “Failed to upload” or “skipped”.

4. v1 / v2 SDK confusion

Firebase Functions is split into v1 (firebase-functions) and v2 (firebase-functions/v2). Different endpoints, slightly different call shapes.

How to spot it: Check imports: import { onCall } from 'firebase-functions/v2/https' (v2) vs import * as functions from 'firebase-functions' (v1).

5. Function garbage-collected by deploy

If a previous deploy didn’t export sendEmail, Firebase deletes it. Next deploy you re-export but the deploy isn’t done — function is missing.

How to spot it: firebase functions:list shows whether it actually exists.

6. CORS blocks the request from ever leaving the browser

HTTPS triggers have CORS rules. Without setting them, cross-origin frontend calls get blocked client-side — looks like 404 but never made it to the server.

How to spot it: Network tab shows status 0 or CORS error, not 404.

Shortest path to fix

Step 1: List functions to confirm existence

firebase functions:list --project my-project-prod

# Example:
# ┌──────────────┬─────────┬───────────────┬─────────┐
# │ Function     │ Version │ Trigger       │ Region  │
# ├──────────────┼─────────┼───────────────┼─────────┤
# │ sendEmail    │ v2      │ https         │ us-east1│
# └──────────────┴─────────┴───────────────┴─────────┘

Confirms name, version, region.

Step 2: Set region in the client SDK

// v2 SDK
import { getFunctions, httpsCallable } from 'firebase/functions';

// ❌ unspecified = us-central1
const fns = getFunctions(app);

// ✅ matches the function
const fns = getFunctions(app, 'us-east1');
const callSendEmail = httpsCallable(fns, 'sendEmail');

Step 3: Declare region in the function code

// v2
import { onCall } from 'firebase-functions/v2/https';

export const sendEmail = onCall(
  { region: 'us-east1', cors: true },  // explicit region
  async (req) => { /* ... */ }
);

Step 4: Re-deploy and watch build logs

firebase deploy --only functions:sendEmail --debug 2>&1 | tee deploy.log

# Grep for issues
grep -i "error\|failed\|skipped" deploy.log

CLI surfaces build failures but they’re easy to miss in long output; --debug adds detail.

Step 5: Verify with the local emulator

firebase emulators:start --only functions

# Client connects to emulator
import { connectFunctionsEmulator } from 'firebase/functions';
if (location.hostname === 'localhost') {
  connectFunctionsEmulator(fns, 'localhost', 5001);
}

Works on emulator = deploy / region issue. Fails on emulator too = code issue.

Step 6: Direct HTTP curl

# v2 onCall endpoint
curl -X POST https://us-east1-my-project.cloudfunctions.net/sendEmail \
  -H "Content-Type: application/json" \
  -d '{"data":{"to":"x"}}'

# 404 = truly not there or wrong region
# 200 / 401 / 403 = exists, different issue (auth / permission)

Step 7: v1 / v2 audit

// v1
import * as functions from 'firebase-functions';
export const sendEmail = functions.https.onCall((data, context) => ...);

// v2
import { onCall } from 'firebase-functions/v2/https';
export const sendEmail = onCall((req) => ...);

Different URL paths. Mixing them calls the wrong place. Pick one version repo-wide.

Prevention

  • One region per project; write it in CLAUDE.md / README; all new functions use the same one
  • Always pass region when initializing the client SDK — never rely on the default
  • Centralize: export const FUNCTIONS_REGION = 'us-east1'; both client and server import it
  • Post-deploy health-check script that curls every endpoint
  • Add a CI typecheck step so build failures don’t slip into deploy
  • Use camelCase for names (matches JS exports); don’t mix in kebab-case
  • v1 → v2 migration: do it all at once; don’t half-v1, half-v2
  • Add “function not found” metrics; alert when it spikes

Tags: #Backend #Debug #Troubleshooting #Firebase