This error occurs when you attempt to create or import a user with a custom UID that already exists in Firebase. Fix it by checking if the user exists first or letting Firebase auto-generate unique UIDs.
This error is thrown by Firebase Admin SDK when you try to create a new user with a custom UID (User ID) that is already in use by another user account. Each user in Firebase Authentication must have a unique identifier, and the system prevents creating duplicate UIDs to maintain data integrity. This typically happens when using the Firebase Admin SDK's `createUser()` method with the `uid` parameter specified, or during batch user imports via the `importUsers()` method. The UID must be unique across your entire Firebase project - no two users can share the same identifier. Since Firebase automatically generates unique UIDs when you don't specify one, this error is usually a result of explicitly setting custom UIDs without proper validation.
Before creating a user with a custom UID, verify that no user with that UID already exists in your Firebase project.
Incorrect - no validation:
import { getAuth } from 'firebase-admin/auth';
// ❌ This will fail if uid already exists
try {
const userRecord = await getAuth().createUser({
uid: 'custom-user-123',
email: '[email protected]',
password: 'securePassword123'
});
} catch (error: any) {
console.error('Failed:', error.code); // auth/uid-already-exists
}Correct - check existence first:
import { getAuth } from 'firebase-admin/auth';
async function createUserSafely(uid: string, email: string, password: string) {
try {
// Check if user already exists
const existingUser = await getAuth().getUser(uid);
console.log('User already exists:', existingUser.uid);
return { success: false, error: 'User already exists' };
} catch (error: any) {
if (error.code === 'auth/user-not-found') {
// User doesn't exist, safe to create
const userRecord = await getAuth().createUser({
uid: uid,
email: email,
password: password
});
console.log('User created successfully:', userRecord.uid);
return { success: true, uid: userRecord.uid };
}
throw error;
}
}
await createUserSafely('custom-user-123', '[email protected]', 'password');The simplest solution is to let Firebase automatically generate unique UIDs instead of specifying custom ones. Firebase-generated UIDs are guaranteed to be unique.
Incorrect - specifying custom UID:
import { getAuth } from 'firebase-admin/auth';
// ❌ Custom UID may already exist
await getAuth().createUser({
uid: 'user-' + userId, // Risky - may conflict
email: '[email protected]',
password: 'password'
});Correct - let Firebase generate UID:
import { getAuth } from 'firebase-admin/auth';
// ✅ Firebase generates unique UID automatically
const userRecord = await getAuth().createUser({
email: '[email protected]',
password: 'password'
});
console.log('User created with auto-generated UID:', userRecord.uid);
// Store the Firebase UID in your database for future reference
await database.collection('users').doc(userRecord.uid).set({
email: userRecord.email,
createdAt: new Date()
});When you need custom UIDs:
If you must use custom UIDs (e.g., migrating from another system), use a format that guarantees uniqueness:
import { getAuth } from 'firebase-admin/auth';
import { v4 as uuidv4 } from 'uuid';
// Generate truly unique UIDs
const uniqueId = `legacy_${Date.now()}_${Math.random().toString(36).substring(7)}`;
// Or use UUID
const uuidBasedId = `user_${uuidv4()}`;
await getAuth().createUser({
uid: uniqueId,
email: '[email protected]'
});When importing multiple users, check for existing UIDs before calling importUsers().
Incorrect - no duplicate handling:
import { getAuth } from 'firebase-admin/auth';
const usersToImport = [
{ uid: 'user-1', email: '[email protected]', passwordHash: hashBuffer1 },
{ uid: 'user-2', email: '[email protected]', passwordHash: hashBuffer2 }
];
// ❌ May fail if any uid already exists
const result = await getAuth().importUsers(usersToImport);Correct - filter out existing users:
import { getAuth } from 'firebase-admin/auth';
async function importUsersWithValidation(usersToImport: any[]) {
// Get all existing UIDs to filter
const existingUids = new Set();
let pageToken: string | undefined;
do {
const page = await getAuth().listUsers(100, pageToken);
page.users.forEach(user => {
existingUids.add(user.uid);
});
pageToken = page.pageToken;
} while (pageToken);
// Filter to only new users
const newUsers = usersToImport.filter(user => !existingUids.has(user.uid));
if (newUsers.length === 0) {
console.log('All users already exist in Firebase');
return { success: false, message: 'No new users to import' };
}
// Import only new users
const result = await getAuth().importUsers(newUsers);
console.log(`Imported ${result.successCount} users`);
console.log(`Failed: ${result.failureCount} users`);
if (result.errors.length > 0) {
result.errors.forEach(err => {
console.error(`Failed to import user at index ${err.index}: ${err.error.message}`);
});
}
return { success: true, result };
}
await importUsersWithValidation(usersToImport);If the user already exists and you need to modify their account, use updateUser() instead of createUser().
Incorrect - tries to create when user exists:
import { getAuth } from 'firebase-admin/auth';
// ❌ Will fail with auth/uid-already-exists
const userRecord = await getAuth().createUser({
uid: 'user-123',
email: '[email protected]'
});Correct - update the existing user:
import { getAuth } from 'firebase-admin/auth';
async function createOrUpdateUser(uid: string, email: string, displayName?: string) {
try {
// Check if user exists
const existingUser = await getAuth().getUser(uid);
// User exists, update instead
const updatedUser = await getAuth().updateUser(uid, {
email: email,
displayName: displayName || existingUser.displayName
});
console.log('User updated:', updatedUser.uid);
return { action: 'updated', user: updatedUser };
} catch (error: any) {
if (error.code === 'auth/user-not-found') {
// User doesn't exist, create new
const newUser = await getAuth().createUser({
uid: uid,
email: email,
displayName: displayName
});
console.log('User created:', newUser.uid);
return { action: 'created', user: newUser };
}
throw error;
}
}
await createOrUpdateUser('user-123', '[email protected]', 'John Doe');Add comprehensive error handling to gracefully manage uid-already-exists errors in production.
Complete example with error handling:
import { getAuth } from 'firebase-admin/auth';
interface UserCreationOptions {
uid: string;
email: string;
displayName?: string;
password?: string;
maxRetries?: number;
}
async function createUserWithRetry(options: UserCreationOptions) {
const { uid, email, displayName, password, maxRetries = 3 } = options;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
// Check if user already exists
try {
const existingUser = await getAuth().getUser(uid);
return {
success: false,
error: 'User already exists',
existingUser: {
uid: existingUser.uid,
email: existingUser.email,
createdAt: existingUser.metadata.creationTime
}
};
} catch (error: any) {
if (error.code !== 'auth/user-not-found') {
throw error;
}
}
// Create user
const userRecord = await getAuth().createUser({
uid: uid,
email: email,
displayName: displayName,
password: password
});
console.log(`User created successfully (attempt ${attempt}): ${userRecord.uid}`);
return {
success: true,
user: {
uid: userRecord.uid,
email: userRecord.email,
createdAt: userRecord.metadata.creationTime
}
};
} catch (error: any) {
if (error.code === 'auth/uid-already-exists') {
console.warn(`UID already exists (attempt ${attempt}/${maxRetries})`);
if (attempt === maxRetries) {
return {
success: false,
error: 'UID already exists and maximum retries exceeded',
code: 'auth/uid-already-exists'
};
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 100 * attempt));
} else if (error.code === 'auth/invalid-argument') {
return {
success: false,
error: 'Invalid user data provided',
details: error.message
};
} else {
throw error;
}
}
}
}
// Usage
const result = await createUserWithRetry({
uid: 'custom-user-123',
email: '[email protected]',
displayName: 'John Doe',
password: 'securePassword123'
});
console.log(result);Custom UIDs vs Auto-Generated UIDs:
Firebase generates UIDs using a CUID format (like "AZ8e9K7mP2xL4q9w1") which is guaranteed to be unique. If you don't have a specific reason to use custom UIDs, let Firebase generate them. Custom UIDs are only necessary when:
1. Migrating users from another system and maintaining their original identifiers
2. Implementing single sign-on (SSO) where the UID must match an external identity provider
3. Ensuring user IDs match your existing database schema
Even in these cases, it's safer to store the external ID separately and use Firebase-generated UIDs as the source of truth.
Concurrent User Creation:
If your application creates users concurrently, ensure proper synchronization:
// Use a database transaction or distributed lock to ensure single creation
async function createUserExclusively(uid: string) {
// Acquire lock on this UID
const lockKey = `lock:user:${uid}`;
// Check if already exists
const user = await getAuth().getUser(uid).catch(() => null);
if (user) return user;
// Create within lock to prevent race conditions
return await getAuth().createUser({ uid });
}Migration Best Practices:
When migrating users from another system:
1. Pre-validate all UIDs are unique across your source data
2. Test with a small batch first
3. Use importUsers() with password hashes for efficiency (no new email verification needed)
4. Log all failures for manual review
5. Have a rollback plan in case of large-scale failures
Testing:
Always test user creation logic in the Firebase Emulator Suite before deploying to production:
firebase emulators:start --only authThe emulator will properly simulate the uid-already-exists error condition.
Callable Functions: INTERNAL - Unhandled exception
How to fix "Callable Functions: INTERNAL - Unhandled exception" in Firebase
auth/invalid-hash-algorithm: Hash algorithm doesn't match supported options
How to fix "auth/invalid-hash-algorithm: Hash algorithm doesn't match supported options" in Firebase
Hosting: CORS configuration not set up properly
How to fix CORS configuration in Firebase Hosting
auth/reserved-claims: Custom claims use reserved OIDC claim names
How to fix "reserved claims" error when setting custom claims in Firebase
Callable Functions: UNAUTHENTICATED - Invalid credentials
How to fix "UNAUTHENTICATED - Invalid credentials" in Firebase Callable Functions