This Firebase Authentication error occurs when attempting to set a user's display name with an empty string, null, or undefined value. The fix involves ensuring you always provide a valid non-empty string when setting the displayName property through createUser(), updateUser(), or updateProfile() methods.
The "auth/invalid-display-name" error in Firebase Authentication indicates that your application tried to set a user's display name with an invalid value. Firebase requires the displayName property to be either a non-empty string or omitted entirely. When you call Firebase Authentication methods like admin.auth().createUser(), admin.auth().updateUser(), or currentUser.updateProfile(), Firebase validates the displayName parameter. If you pass an empty string (""), null, undefined, or any non-string value, Firebase rejects the operation with this error. This validation exists because display names are meant to identify users in your application's UI. An empty or invalid display name could cause confusion or display issues. Firebase enforces this rule at the API level to maintain data integrity across all authentication methods.
Add validation to ensure displayName is never empty before calling Firebase methods:
Client-side validation (Web):
import { getAuth, updateProfile } from "firebase/auth";
const auth = getAuth();
const user = auth.currentUser;
async function updateUserDisplayName(newDisplayName) {
// Validate before updating
if (!newDisplayName || newDisplayName.trim().length === 0) {
console.error('Display name cannot be empty');
return { error: 'Please provide a valid display name' };
}
try {
await updateProfile(user, {
displayName: newDisplayName.trim() // Remove leading/trailing spaces
});
console.log('Display name updated successfully');
return { success: true };
} catch (error) {
if (error.code === 'auth/invalid-display-name') {
console.error('Invalid display name:', error.message);
}
return { error: error.message };
}
}Server-side validation (Admin SDK):
const admin = require('firebase-admin');
async function updateUserDisplayNameAdmin(uid, displayName) {
// Validate before updating
if (!displayName || typeof displayName !== 'string' || displayName.trim().length === 0) {
throw new Error('Display name must be a non-empty string');
}
try {
await admin.auth().updateUser(uid, {
displayName: displayName.trim()
});
console.log('User display name updated');
} catch (error) {
if (error.code === 'auth/invalid-display-name') {
console.error('Invalid display name provided');
}
throw error;
}
}Key validation points:
1. Check for null or undefined
2. Verify it's a string type
3. Ensure length > 0 after trimming whitespace
4. Trim leading/trailing spaces before saving
Add validation to user registration and profile update forms:
HTML form with validation:
<form id="registration-form">
<div>
<label for="email">Email:</label>
<input
type="email"
id="email"
name="email"
required
/>
</div>
<div>
<label for="displayName">Display Name:</label>
<input
type="text"
id="displayName"
name="displayName"
required
minlength="1"
maxlength="100"
placeholder="Enter your name"
/>
<span class="error" id="displayName-error"></span>
</div>
<div>
<label for="password">Password:</label>
<input
type="password"
id="password"
name="password"
required
/>
</div>
<button type="submit">Register</button>
</form>JavaScript form handler:
import { getAuth, createUserWithEmailAndPassword, updateProfile } from "firebase/auth";
const auth = getAuth();
const form = document.getElementById('registration-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const email = form.email.value;
const password = form.password.value;
const displayName = form.displayName.value.trim();
// Validate display name
const errorElement = document.getElementById('displayName-error');
if (!displayName || displayName.length === 0) {
errorElement.textContent = 'Display name is required';
return;
}
if (displayName.length < 2) {
errorElement.textContent = 'Display name must be at least 2 characters';
return;
}
try {
// Create user account
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
// Update profile with display name
await updateProfile(userCredential.user, {
displayName: displayName
});
console.log('User registered with display name:', displayName);
// Redirect to dashboard or show success message
} catch (error) {
if (error.code === 'auth/invalid-display-name') {
errorElement.textContent = 'Please provide a valid display name';
} else {
errorElement.textContent = error.message;
}
}
});React form with validation:
import { useState } from 'react';
import { getAuth, createUserWithEmailAndPassword, updateProfile } from "firebase/auth";
function RegistrationForm() {
const [displayName, setDisplayName] = useState('');
const [error, setError] = useState('');
const auth = getAuth();
const validateDisplayName = (name) => {
if (!name || name.trim().length === 0) {
return 'Display name is required';
}
if (name.trim().length < 2) {
return 'Display name must be at least 2 characters';
}
return null;
};
const handleSubmit = async (e) => {
e.preventDefault();
const validationError = validateDisplayName(displayName);
if (validationError) {
setError(validationError);
return;
}
try {
const userCredential = await createUserWithEmailAndPassword(
auth,
email,
password
);
await updateProfile(userCredential.user, {
displayName: displayName.trim()
});
// Success - redirect or update UI
} catch (error) {
setError(error.message);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={displayName}
onChange={(e) => setDisplayName(e.target.value)}
placeholder="Display Name"
required
/>
{error && <span className="error">{error}</span>}
<button type="submit">Register</button>
</form>
);
}If displayName is optional in your application, omit it entirely instead of passing empty values:
Incorrect approach (causes error):
// DON'T do this
await admin.auth().createUser({
email: '[email protected]',
password: 'securePassword123',
displayName: '' // This will cause auth/invalid-display-name
});
// DON'T do this either
await admin.auth().updateUser(uid, {
displayName: null // This will also cause the error
});Correct approach (omit empty values):
// Option 1: Build object conditionally
const userProperties = {
email: '[email protected]',
password: 'securePassword123'
};
// Only add displayName if it has a value
if (displayName && displayName.trim().length > 0) {
userProperties.displayName = displayName.trim();
}
await admin.auth().createUser(userProperties);// Option 2: Use object spread with conditional property
const displayNameValue = 'John Doe'; // Could be empty string
await admin.auth().createUser({
email: '[email protected]',
password: 'securePassword123',
...(displayNameValue && displayNameValue.trim().length > 0 && {
displayName: displayNameValue.trim()
})
});// Option 3: Helper function for clean updates
function buildUserUpdateObject(updates) {
const cleanUpdates = {};
if (updates.email) cleanUpdates.email = updates.email;
if (updates.password) cleanUpdates.password = updates.password;
if (updates.displayName && updates.displayName.trim().length > 0) {
cleanUpdates.displayName = updates.displayName.trim();
}
if (updates.photoURL) cleanUpdates.photoURL = updates.photoURL;
return cleanUpdates;
}
// Usage
const updates = buildUserUpdateObject({
displayName: userInput.displayName, // Could be empty
photoURL: userInput.photoURL
});
await admin.auth().updateUser(uid, updates);Key principle: If a field is optional, don't include it in the update object at all rather than passing empty/null values.
Review and fix common patterns that inadvertently pass empty display names:
Pattern 1: Unvalidated form data
// WRONG - directly using form data without validation
const formData = new FormData(form);
await updateProfile(user, {
displayName: formData.get('displayName') // Could be empty!
});
// CORRECT - validate first
const displayName = formData.get('displayName');
if (displayName && displayName.trim().length > 0) {
await updateProfile(user, {
displayName: displayName.trim()
});
}Pattern 2: Object destructuring with defaults
// WRONG - empty string as default
const { displayName = '' } = userData;
await admin.auth().updateUser(uid, { displayName });
// CORRECT - use undefined or check before using
const { displayName } = userData;
if (displayName && displayName.trim().length > 0) {
await admin.auth().updateUser(uid, { displayName: displayName.trim() });
}Pattern 3: API request handlers
// WRONG - trusting client input
app.post('/api/update-profile', async (req, res) => {
const { displayName } = req.body;
await admin.auth().updateUser(req.user.uid, { displayName });
});
// CORRECT - validate server-side
app.post('/api/update-profile', async (req, res) => {
const { displayName } = req.body;
if (!displayName || typeof displayName !== 'string' || displayName.trim().length === 0) {
return res.status(400).json({
error: 'Display name must be a non-empty string'
});
}
try {
await admin.auth().updateUser(req.user.uid, {
displayName: displayName.trim()
});
res.json({ success: true });
} catch (error) {
res.status(400).json({ error: error.message });
}
});Pattern 4: Copying data from other auth providers
// WRONG - provider might not have displayName
const providerData = result.user.providerData[0];
await admin.auth().updateUser(uid, {
displayName: providerData.displayName // Could be null!
});
// CORRECT - check existence first
const providerData = result.user.providerData[0];
if (providerData.displayName && providerData.displayName.length > 0) {
await admin.auth().updateUser(uid, {
displayName: providerData.displayName
});
} else {
console.log('Provider did not provide display name');
}Create reusable validation utilities to prevent this error across your codebase:
Validation utility module:
// utils/firebase-validation.js
/**
* Validates a display name for Firebase Authentication
* @param {string} displayName - The display name to validate
* @returns {object} Validation result with isValid and error properties
*/
export function validateDisplayName(displayName) {
if (displayName === null || displayName === undefined) {
return {
isValid: false,
error: 'Display name is required'
};
}
if (typeof displayName !== 'string') {
return {
isValid: false,
error: 'Display name must be a string'
};
}
const trimmed = displayName.trim();
if (trimmed.length === 0) {
return {
isValid: false,
error: 'Display name cannot be empty'
};
}
if (trimmed.length < 2) {
return {
isValid: false,
error: 'Display name must be at least 2 characters'
};
}
if (trimmed.length > 100) {
return {
isValid: false,
error: 'Display name cannot exceed 100 characters'
};
}
return {
isValid: true,
value: trimmed
};
}
/**
* Sanitizes user properties for Firebase Auth methods
* Removes empty or invalid values
*/
export function sanitizeUserProperties(properties) {
const sanitized = {};
if (properties.email) {
sanitized.email = properties.email;
}
if (properties.password) {
sanitized.password = properties.password;
}
if (properties.displayName) {
const validation = validateDisplayName(properties.displayName);
if (validation.isValid) {
sanitized.displayName = validation.value;
}
}
if (properties.photoURL && properties.photoURL.trim().length > 0) {
sanitized.photoURL = properties.photoURL.trim();
}
if (properties.phoneNumber) {
sanitized.phoneNumber = properties.phoneNumber;
}
return sanitized;
}Usage in your application:
import { validateDisplayName, sanitizeUserProperties } from './utils/firebase-validation';
import { getAuth, updateProfile } from 'firebase/auth';
const auth = getAuth();
async function updateUserProfile(displayName, photoURL) {
// Validate display name
const validation = validateDisplayName(displayName);
if (!validation.isValid) {
console.error(validation.error);
return { error: validation.error };
}
try {
// Safe to use validated value
await updateProfile(auth.currentUser, {
displayName: validation.value,
photoURL: photoURL
});
return { success: true };
} catch (error) {
return { error: error.message };
}
}
// Or use sanitize for batch updates
async function createUserAccount(userData) {
const sanitized = sanitizeUserProperties(userData);
try {
await admin.auth().createUser(sanitized);
return { success: true };
} catch (error) {
return { error: error.message };
}
}TypeScript type safety:
interface DisplayNameValidation {
isValid: boolean;
error?: string;
value?: string;
}
export function validateDisplayName(displayName: unknown): DisplayNameValidation {
// Implementation as above
}### Display Name Requirements and Limitations
Firebase displayName specifications:
- Must be a string type
- Cannot be empty string ("")
- Cannot be null or undefined when explicitly set
- Can contain any UTF-8 characters including emojis
- No enforced maximum length by Firebase, but recommended 100 characters or less
- Optional field - can be omitted entirely during user creation/updates
Character support:
// All of these are valid display names
const validNames = [
"John Doe", // Basic Latin
"María García", // Latin with accents
"Владимир", // Cyrillic
"李明", // Chinese characters
"محمد", // Arabic
"John 🔥 Doe", // With emoji
"user_123", // With numbers/underscores
"O'Brien", // With apostrophe
];### Display Name vs Other User Properties
Comparison with other Firebase Auth properties:
| Property | Required | Can be empty | Validation |
|----------|----------|--------------|------------|
| email | Yes | No | Must be valid email format |
| password | Yes (for email/password) | No | Min 6 characters |
| displayName | No | No (if set) | Non-empty string |
| photoURL | No | No (if set) | Valid URL format |
| phoneNumber | No (for phone auth) | No | E.164 format |
### Common Integration Scenarios
Social login providers and displayName:
Different OAuth providers handle display names differently:
1. Google Sign-In: Always provides displayName from Google account
2. Facebook Login: Provides name, but may require permissions
3. GitHub: Provides name if set in GitHub profile
4. Apple Sign-In: May not provide name if user opts out
5. Twitter: Provides display name from Twitter profile
Handling provider differences:
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";
const auth = getAuth();
async function signInAndEnsureDisplayName(provider) {
const result = await signInWithPopup(auth, provider);
const user = result.user;
// Check if provider gave us a display name
if (!user.displayName || user.displayName.trim().length === 0) {
// Prompt user to set display name
const customName = await promptUserForDisplayName();
if (customName && customName.trim().length > 0) {
await updateProfile(user, {
displayName: customName.trim()
});
}
}
return user;
}### Security and Privacy Considerations
Display name as user-facing content:
Display names are often shown publicly in your application, so consider:
1. XSS prevention: Firebase doesn't sanitize displayName content
// Always escape when displaying
import DOMPurify from 'dompurify';
const safeDisplayName = DOMPurify.sanitize(user.displayName);2. Content moderation: Implement profanity filtering if needed
import Filter from 'bad-words';
const filter = new Filter();
function validateAndCleanDisplayName(name) {
if (!name || name.trim().length === 0) {
return { error: 'Display name required' };
}
const cleaned = name.trim();
if (filter.isProfane(cleaned)) {
return { error: 'Display name contains inappropriate content' };
}
return { value: cleaned };
}3. Length limits: Consider UX when displaying long names
4. Uniqueness: displayName is NOT unique - don't use for identification
Privacy considerations:
- Users may not want to use real names
- Consider allowing usernames separate from displayName
- Provide option to change displayName easily
- Don't require sensitive information in display names
### Migration and Backward Compatibility
Handling existing users without display names:
// Check and update users missing display names
async function migrateUsersWithoutDisplayNames() {
const listUsersResult = await admin.auth().listUsers(1000);
for (const userRecord of listUsersResult.users) {
if (!userRecord.displayName || userRecord.displayName.trim().length === 0) {
// Generate default display name from email
const defaultName = userRecord.email?.split('@')[0] || 'User';
try {
await admin.auth().updateUser(userRecord.uid, {
displayName: defaultName
});
console.log(`Updated user ${userRecord.uid} with display name: ${defaultName}`);
} catch (error) {
console.error(`Failed to update user ${userRecord.uid}:`, error);
}
}
}
}### Testing Display Name Validation
Unit tests for validation:
describe('validateDisplayName', () => {
test('rejects empty string', () => {
const result = validateDisplayName('');
expect(result.isValid).toBe(false);
});
test('rejects null', () => {
const result = validateDisplayName(null);
expect(result.isValid).toBe(false);
});
test('rejects undefined', () => {
const result = validateDisplayName(undefined);
expect(result.isValid).toBe(false);
});
test('trims whitespace', () => {
const result = validateDisplayName(' John Doe ');
expect(result.isValid).toBe(true);
expect(result.value).toBe('John Doe');
});
test('accepts valid names', () => {
const result = validateDisplayName('John Doe');
expect(result.isValid).toBe(true);
expect(result.value).toBe('John Doe');
});
});### Error Recovery Strategies
Graceful degradation when displayName is unavailable:
function getUserDisplayText(user) {
// Fallback chain
return user.displayName ||
user.email?.split('@')[0] ||
user.phoneNumber ||
'Anonymous User';
}
// Usage in UI
function UserProfile({ user }) {
const displayText = getUserDisplayText(user);
return (
<div>
<h2>{displayText}</h2>
{!user.displayName && (
<p>
<a href="/profile/edit">Set your display name</a>
</p>
)}
</div>
);
}Callable Functions: INTERNAL - Unhandled exception
How to fix "Callable Functions: INTERNAL - Unhandled exception" in Firebase
messaging/UNSPECIFIED_ERROR: No additional information available
How to fix "messaging/UNSPECIFIED_ERROR: No additional information available" in Firebase Cloud Messaging
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
App Check: reCAPTCHA Score Too Low
App Check reCAPTCHA Score Too Low
storage/invalid-url: Invalid URL format for Cloud Storage reference
How to fix invalid URL format in Firebase Cloud Storage