1

I have a Next.js application on Vercel. My API route fails when calling Firestore's doc() function, but only when deployed to Vercel or when running the production build locally. The dev server (npm run dev) sometimes gives a different error (Unauthorized) but the production build is consistent.

The error I get from the Vercel logs and my local production server is:

Error: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore code: 'invalid-argument'

This happens in my /api/stripe-connect/route.ts file when it tries to read a Firestore document.

/api/stripe-connect/route.ts:

import { NextRequest, NextResponse } from 'next/server';
import { Stripe } from 'stripe';
import { doc, getDoc, updateDoc } from 'firebase/firestore'; // These are client-side SDK functions
import { db as adminDb, adminApp } from '@/lib/firebase-admin-lazy'; 
import { getAuth } from 'firebase-admin/auth';

// Assume Stripe initialization and getUserIdFromRequest function are here
// For example:
// const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, { apiVersion: '2023-10-16' });
// async function getUserIdFromRequest(req: NextRequest): Promise<string | null> {
//   // ... logic to get user ID, e.g., from auth token
//   return 'some-user-id'; 
// }


export async function POST(req: NextRequest) {
  // ... (rest of your POST function logic)
  const userId = await getUserIdFromRequest(req); // Assuming this function exists and works

  if (!userId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  // THE ERROR IS TRIGGERED BY THIS LINE:
  // This `doc` function is from the client-side SDK, expecting client-side Firestore instance
  const performerDocRef = doc(adminDb, 'performers', userId); 
  const performerSnap = await getDoc(performerDocRef);
  // ... (rest of your POST function logic)
  return NextResponse.json({ message: 'Processed' });
}

My Firebase Admin initialization file (/lib/firebase-admin-lazy.ts):

import { cert, getApp, initializeApp, AppOptions, App } from 'firebase-admin/app';
import { getFirestore, FieldValue, Timestamp, Firestore } from 'firebase-admin/firestore';
import { getAuth, Auth } from 'firebase-admin/auth';

let adminApp: App;
let db: Firestore;
let auth: Auth;

try {
  adminApp = getApp();
} catch (error) {
  const serviceAccountString = process.env.FIREBASE_SERVICE_ACCOUNT;
  if (!serviceAccountString) {
    throw new Error('The FIREBASE_SERVICE_ACCOUNT environment variable is not set.');
  }
  try {
    const serviceAccount = JSON.parse(serviceAccountString);
    const options: AppOptions = {
      credential: cert(serviceAccount),
    };
    adminApp = initializeApp(options);
  } catch (parseError) {
    console.error('Failed to parse FIREBASE_SERVICE_ACCOUNT.', parseError);
    throw new Error('The FIREBASE_SERVICE_ACCOUNT environment variable is not valid JSON.');
  }
}

db = getFirestore(adminApp);
auth = getAuth(adminApp);

export { adminApp, db, auth, FieldValue, Timestamp }; 

I have confirmed my FIREBASE_SERVICE_ACCOUNT JSON key is correct in my Vercel environment variables and my .env.local file. The service account has the "Firebase Admin SDK Administrator Service Agent" role.

Why is the db object exported from firebase-admin-lazy.ts invalid when used inside a Vercel API Route with the client-side Firestore doc() function, and what is the correct way to initialize and export the Firebase Admin SDK for use with its native methods in this environment?

1 Answer 1

1

You're mixing use of the Firestore client SDK firebase/firestore and the Firebase admin SDK wrapper firebase-admin/firestore. They are not compatible with each other. If you intend to use the Firebase Admin SDK for access on your backend, you should use only that, and not the client SDK at the same time.

The admin SDK doesn't expose functions like doc() and collection(). Instead it has objects for building document references and querying them. You should refer to the documentation and make sure the code samples have been switched to nodejs instead of the web client SDK so that you're looking at the correct examples. Also, use the Firebase Admin API reference for more details and examples.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.