This Firebase Authentication error occurs when you try to update a user's 'disabled' property with a non-boolean value. The 'disabled' field must be either true or false, and this error appears when passing strings, numbers, null, or undefined instead. The fix involves ensuring you pass a proper boolean value when enabling or disabling user accounts.
The "auth/invalid-disabled-field" error in Firebase Authentication indicates that your code is attempting to set a user's 'disabled' status with an invalid value. The 'disabled' property is a boolean field that controls whether a user account is active or disabled. When you use Firebase Admin SDK methods like `updateUser()` or `createUser()`, the 'disabled' field must be a strict boolean (true or false). Firebase validates this input and rejects any non-boolean values to prevent ambiguous account states. This error commonly appears when: 1. Passing a string like "true" or "false" instead of boolean true/false 2. Using numbers (0 or 1) to represent boolean states 3. Passing null or undefined when a boolean is expected 4. Using truthy/falsy values from JavaScript that aren't strict booleans 5. Incorrectly parsing boolean values from configuration or user input The 'disabled' property is important for account management: - `disabled: true`: User cannot sign in, but account data is preserved - `disabled: false`: User can sign in normally - This is different from deleting a user account entirely
First, check that you're passing a strict boolean (true/false) not a string or number:
Common incorrect patterns:
// INCORRECT - These will cause the error
const userUpdate = {
disabled: "true", // String instead of boolean
disabled: "false", // String instead of boolean
disabled: 1, // Number instead of boolean
disabled: 0, // Number instead of boolean
disabled: null, // null instead of boolean
disabled: undefined, // undefined instead of boolean
disabled: "1", // String number instead of boolean
};
// CORRECT - These will work
const userUpdate = {
disabled: true, // Boolean true
disabled: false, // Boolean false
};Check your update code:
// Firebase Admin SDK example
const admin = require('firebase-admin');
// INCORRECT - Using string from request body
app.post('/disable-user', async (req, res) => {
const { userId, disabled } = req.body; // 'disabled' might be string "true"
try {
await admin.auth().updateUser(userId, {
disabled: disabled, // ERROR if disabled is string
});
} catch (error) {
if (error.code === 'auth/invalid-disabled-field') {
console.error('Invalid boolean value:', disabled, typeof disabled);
}
}
});
// CORRECT - Convert to boolean
app.post('/disable-user', async (req, res) => {
const { userId, disabled } = req.body;
// Convert string to boolean
const isDisabled = disabled === 'true' || disabled === true;
try {
await admin.auth().updateUser(userId, {
disabled: isDisabled, // Proper boolean
});
} catch (error) {
// Handle error
}
});Ensure proper boolean conversion in your code:
String to boolean conversion:
// Common conversion patterns
const str = "true";
const bool = str === "true"; // true
const str2 = "false";
const bool2 = str2 === "true"; // false
const str3 = "1";
const bool3 = Boolean(parseInt(str3)); // true (but careful with 0)
// Better: explicit conversion function
function toBoolean(value) {
if (typeof value === 'boolean') return value;
if (typeof value === 'string') {
if (value.toLowerCase() === 'true') return true;
if (value.toLowerCase() === 'false') return false;
if (value === '1') return true;
if (value === '0') return false;
}
if (typeof value === 'number') {
return value !== 0;
}
return false; // Default for null, undefined, etc.
}
// Usage
const userUpdate = {
disabled: toBoolean(req.body.disabled),
};JSON parsing issues:
// JSON doesn't have boolean type - it's parsed as string
const config = JSON.parse('{"disabled": "true"}');
console.log(config.disabled); // "true" (string)
console.log(typeof config.disabled); // "string"
// Fix: parse with reviver function
const config2 = JSON.parse('{"disabled": "true"}', (key, value) => {
if (key === 'disabled') {
return value === 'true' || value === true;
}
return value;
});
console.log(config2.disabled); // true (boolean)
console.log(typeof config2.disabled); // "boolean"Database value mapping:
// Common issue: database stores 0/1, but Firebase needs true/false
const dbUser = await database.getUser(userId);
// dbUser.isDisabled might be 0 or 1 (number)
const firebaseUpdate = {
disabled: dbUser.isDisabled === 1, // Convert number to boolean
};
// Or if database uses string 'Y'/'N'
const firebaseUpdate2 = {
disabled: dbUser.status === 'Y', // Convert string to boolean
};Use Firebase Admin SDK correctly with boolean values:
Basic user update:
const admin = require('firebase-admin');
// Initialize Firebase Admin
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
// Disable a user account
async function disableUser(userId) {
try {
await admin.auth().updateUser(userId, {
disabled: true, // Must be boolean true
});
console.log('User ' + userId + ' disabled successfully');
} catch (error) {
if (error.code === 'auth/invalid-disabled-field') {
console.error('Boolean value issue:', error.message);
}
}
}
// Enable a user account
async function enableUser(userId) {
try {
await admin.auth().updateUser(userId, {
disabled: false, // Must be boolean false
});
console.log('User ' + userId + ' enabled successfully');
} catch (error) {
if (error.code === 'auth/invalid-disabled-field') {
console.error('Boolean value issue:', error.message);
}
}
}
// Create user with disabled status
async function createDisabledUser(email, password) {
try {
const user = await admin.auth().createUser({
email: email,
password: password,
disabled: true, // New account starts disabled
});
return user;
} catch (error) {
if (error.code === 'auth/invalid-disabled-field') {
console.error('Check disabled field in createUser:', error);
}
throw error;
}
}Batch updates with proper booleans:
// Process multiple users
async function updateMultipleUsers(userUpdates) {
const updates = userUpdates.map(async (update) => {
// Ensure disabled is boolean
const disabledBool = typeof update.disabled === 'boolean'
? update.disabled
: update.disabled === 'true' || update.disabled === true;
return admin.auth().updateUser(update.userId, {
disabled: disabledBool,
// other fields...
});
});
try {
await Promise.all(updates);
console.log('Batch update successful');
} catch (error) {
console.error('Batch update failed:', error.message);
}
}Add validation middleware to ensure boolean values:
Express.js validation middleware:
const express = require('express');
const { body, validationResult } = require('express-validator');
const app = express();
app.use(express.json());
// Validation middleware for disabled field
const validateDisabledField = [
body('disabled')
.optional()
.custom((value) => {
// Accept boolean, or string 'true'/'false'
if (typeof value === 'boolean') return true;
if (typeof value === 'string' && (value === 'true' || value === 'false')) {
return true;
}
throw new Error('disabled must be boolean or string "true"/"false"');
})
.toBoolean(), // Convert string to boolean
];
// API endpoint with validation
app.put('/api/users/:userId/status', validateDisabledField, async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { userId } = req.params;
const { disabled } = req.body; // Now guaranteed to be boolean
try {
await admin.auth().updateUser(userId, { disabled });
res.json({ success: true, disabled });
} catch (error) {
if (error.code === 'auth/invalid-disabled-field') {
res.status(400).json({ error: 'Invalid disabled value after validation' });
} else {
res.status(500).json({ error: error.message });
}
}
});TypeScript type safety:
interface UserUpdateRequest {
disabled?: boolean; // Explicit boolean type
// other fields...
}
async function updateUserStatus(
userId: string,
update: UserUpdateRequest
): Promise<void> {
// TypeScript ensures disabled is boolean or undefined
if (update.disabled !== undefined && typeof update.disabled !== 'boolean') {
throw new Error('disabled must be boolean');
}
await admin.auth().updateUser(userId, update);
}
// API handler with TypeScript
app.put('/users/:id', async (req: Request, res: Response) => {
const update = req.body as UserUpdateRequest;
// Runtime validation (since TypeScript types are compile-time)
if (update.disabled !== undefined && typeof update.disabled !== 'boolean') {
return res.status(400).json({
error: 'disabled must be boolean true or false'
});
}
// Now safe to use
await updateUserStatus(req.params.id, update);
res.json({ success: true });
});Create test cases to verify boolean handling:
Test script for boolean conversion:
// test-boolean-conversion.js
const testCases = [
{ input: true, expected: true, description: 'boolean true' },
{ input: false, expected: false, description: 'boolean false' },
{ input: 'true', expected: true, description: 'string "true"' },
{ input: 'false', expected: false, description: 'string "false"' },
{ input: 'TRUE', expected: true, description: 'uppercase string' },
{ input: 'FALSE', expected: false, description: 'uppercase string' },
{ input: 1, expected: true, description: 'number 1' },
{ input: 0, expected: false, description: 'number 0' },
{ input: null, expected: false, description: 'null' },
{ input: undefined, expected: false, description: 'undefined' },
{ input: 'yes', expected: false, description: 'invalid string' },
];
function convertToBoolean(value) {
if (typeof value === 'boolean') return value;
if (typeof value === 'string') {
const lower = value.toLowerCase();
if (lower === 'true') return true;
if (lower === 'false') return false;
if (lower === '1') return true;
if (lower === '0') return false;
}
if (typeof value === 'number') {
return value !== 0;
}
return false;
}
console.log('Testing boolean conversion:');
testCases.forEach(({ input, expected, description }) => {
const result = convertToBoolean(input);
const passed = result === expected;
console.log(
(passed ? '✓' : '✗') + ' ' + description + ': ' + JSON.stringify(input) + ' -> ' + result + ' ' +
(passed ? '' : '(expected ' + expected + ')')
);
});Integration test with Firebase:
// test-firebase-disabled.js
const admin = require('firebase-admin');
// Mock or use test Firebase project
async function testDisabledField() {
const testUser = await admin.auth().createUser({
email: '[email protected]',
password: 'test123',
});
console.log('Testing disabled field updates...');
// Test 1: Boolean true (should work)
try {
await admin.auth().updateUser(testUser.uid, { disabled: true });
console.log('✓ Boolean true works');
} catch (error) {
console.log('✗ Boolean true failed:', error.message);
}
// Test 2: Boolean false (should work)
try {
await admin.auth().updateUser(testUser.uid, { disabled: false });
console.log('✓ Boolean false works');
} catch (error) {
console.log('✗ Boolean false failed:', error.message);
}
// Test 3: String "true" (should fail)
try {
await admin.auth().updateUser(testUser.uid, { disabled: "true" });
console.log('✗ String "true" should have failed but worked');
} catch (error) {
if (error.code === 'auth/invalid-disabled-field') {
console.log('✓ String "true" correctly rejected');
} else {
console.log('✗ Unexpected error:', error.message);
}
}
// Cleanup
await admin.auth().deleteUser(testUser.uid);
}
testDisabledField().catch(console.error);Add logging and monitoring for boolean conversion issues:
Enhanced error logging:
// error-logging-middleware.js
function createErrorLogger() {
return (error, req, res, next) => {
if (error.code === 'auth/invalid-disabled-field') {
// Log detailed information about the invalid value
console.error('Invalid disabled field error:', {
timestamp: new Date().toISOString(),
userId: req.params?.userId,
disabledValue: req.body?.disabled,
disabledType: typeof req.body?.disabled,
requestId: req.id,
userAgent: req.get('User-Agent'),
ip: req.ip,
});
// Send helpful error response
res.status(400).json({
error: 'Invalid disabled field',
message: 'The "disabled" field must be a boolean (true or false)',
received: req.body?.disabled,
receivedType: typeof req.body?.disabled,
suggestion: 'Pass true or false (not strings like "true")',
});
return;
}
next(error);
};
}
// Usage
app.use(createErrorLogger());Input validation helper:
// validation-helper.js
function validateFirebaseUserUpdate(update) {
const errors = [];
if (update.disabled !== undefined) {
if (typeof update.disabled !== 'boolean') {
errors.push({
field: 'disabled',
problem: 'must be boolean',
received: update.disabled,
receivedType: typeof update.disabled,
});
}
}
// Check other fields...
return {
isValid: errors.length === 0,
errors,
sanitized: {
...update,
// Convert string booleans if needed
disabled: update.disabled !== undefined
? (typeof update.disabled === 'boolean'
? update.disabled
: update.disabled === 'true' || update.disabled === true)
: undefined,
},
};
}
// Usage in API
app.put('/users/:id', async (req, res) => {
const validation = validateFirebaseUserUpdate(req.body);
if (!validation.isValid) {
return res.status(400).json({
error: 'Validation failed',
details: validation.errors,
});
}
try {
await admin.auth().updateUser(req.params.id, validation.sanitized);
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});Monitoring dashboard:
// Track disabled field errors over time
const errorStats = {
'auth/invalid-disabled-field': {
count: 0,
lastOccurred: null,
commonValues: new Map(),
},
};
function trackAuthError(error, context) {
if (error.code === 'auth/invalid-disabled-field') {
errorStats['auth/invalid-disabled-field'].count++;
errorStats['auth/invalid-disabled-field'].lastOccurred = new Date();
// Track what invalid values are being passed
const invalidValue = context?.disabledValue;
if (invalidValue !== undefined) {
const stats = errorStats['auth/invalid-disabled-field'].commonValues;
stats.set(invalidValue, (stats.get(invalidValue) || 0) + 1);
}
// Log to monitoring service
console.log('Disabled field error tracked:', {
count: errorStats['auth/invalid-disabled-field'].count,
invalidValue,
context,
});
}
}### Understanding the 'disabled' Property in Firebase Authentication
The 'disabled' property in Firebase Authentication serves an important security and administrative function:
Purpose:
- Temporarily prevent a user from signing in without deleting their account
- Preserve user data, preferences, and history
- Allow re-enabling the account later
- Useful for administrative actions, security incidents, or compliance requirements
Difference from Deletion:
- Disabled account: User data preserved, can be re-enabled
- Deleted account: User data removed (with some exceptions), cannot be recovered
Common Use Cases:
1. Temporary suspension: For policy violations or security reviews
2. Compliance requirements: Legal holds or investigations
3. Billing issues: Non-payment of subscription fees
4. Security incidents: Suspected account compromise
5. User requests: Temporary account deactivation
### Boolean Type Strictness in Firebase
Firebase Admin SDK is strict about boolean types for several reasons:
Type Safety:
- Prevents ambiguous states (is "0" false or a string?)
- Ensures consistent behavior across all Firebase services
- Reduces bugs from type coercion edge cases
Common Type Coercion Pitfalls:
// JavaScript truthiness can be misleading
Boolean("false") // true (non-empty string)
Boolean(0) // false
Boolean("0") // true (non-empty string)
Boolean(null) // false
Boolean(undefined) // false
Boolean([]) // true
Boolean({}) // trueFirebase's Approach:
- Requires explicit true or false
- Rejects strings, numbers, null, undefined
- Consistent with Firebase's strongly-typed API design
### Migration Scenarios
Migrating from databases with different boolean representations:
1. MySQL/PostgreSQL: Often use TINYINT(1) or BOOLEAN (0/1)
2. MongoDB: Uses actual boolean type
3. SQLite: No native boolean, uses INTEGER (0/1)
4. CSV/Excel: Often use "Y"/"N", "1"/"0", "TRUE"/"FALSE"
Migration strategy:
async function migrateUsersToFirebase(legacyUsers) {
for (const legacyUser of legacyUsers) {
// Convert various boolean representations
let disabled = false;
if (typeof legacyUser.disabled === 'boolean') {
disabled = legacyUser.disabled;
} else if (typeof legacyUser.disabled === 'number') {
disabled = legacyUser.disabled === 1;
} else if (typeof legacyUser.disabled === 'string') {
const lower = legacyUser.disabled.toLowerCase();
disabled = lower === 'true' || lower === '1' || lower === 'y' || lower === 'yes';
}
await admin.auth().updateUser(legacyUser.firebaseUid, { disabled });
}
}### Security Considerations
Account Disabling vs Deletion:
- Disabling: Use for temporary suspensions, preserves audit trails
- Deletion: Use when user requests account removal (GDPR/CCPA)
- Legal holds: Disable rather than delete during investigations
Access Control:
- Only administrators should be able to disable/enable accounts
- Implement proper role-based access control (RBAC)
- Log all disable/enable actions for audit purposes
Re-enabling Accounts:
- Consider requiring additional verification
- Notify user when account is re-enabled
- Reset sensitive data if account was compromised
### Performance Considerations
Batch Operations:
- Use auth().updateUser() for individual users
- For bulk updates, consider Firebase Auth's import/export features
- Implement rate limiting to avoid quota limits
Caching:
- Firebase Auth caches user data
- Disabled status changes may take a few seconds to propagate
- Consider this in your application logic
### Testing Strategies
Unit Tests:
- Test boolean conversion functions
- Test validation middleware
- Test error handling for invalid values
Integration Tests:
- Test with actual Firebase project (use emulator for development)
- Test edge cases (null, undefined, various string formats)
- Test batch operations
End-to-End Tests:
- Test complete user disable/enable flows
- Test error messages shown to users/admins
- Test audit logging
### Common Integration Issues
Frontend Frameworks:
- React: Form inputs often return strings, need conversion
- Angular: Template-driven forms may pass strings
- Vue: v-model with checkbox returns boolean, but custom inputs may not
API Design:
- Accept both boolean and string "true"/"false" in your API
- Convert to boolean before calling Firebase
- Document the expected format clearly
Database Sync:
- If syncing with another database, ensure boolean consistency
- Consider triggers or middleware to handle type conversion
- Document the mapping between systems
### Firebase Emulator Testing
Use the Firebase Auth Emulator for development testing:
# Start Firebase emulators
firebase emulators:start --only auth
# Configure your app to use emulator// Configure for emulator
if (process.env.NODE_ENV === 'development') {
connectAuthEmulator(auth, 'http://localhost:9099');
}Benefits:
- Test boolean validation without hitting production quotas
- Rapid iteration on boolean conversion logic
- No cost for failed authentication calls
- Isolated testing environment
messaging/UNSPECIFIED_ERROR: No additional information available
How to fix "messaging/UNSPECIFIED_ERROR: No additional information available" in Firebase Cloud Messaging
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
auth/missing-uid: User ID identifier required
How to fix "auth/missing-uid: User ID identifier required" in Firebase
auth/invalid-argument: Invalid parameter passed to method
How to fix "auth/invalid-argument: Invalid parameter passed to method" in Firebase