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?