[READ] Step 1: Are you in the right place?
Yes — bug in the auth component of this repo (typing + runtime divergence between createUser and updateUser).
[REQUIRED] Step 2: Describe your environment
- Operating System version: macOS 15.2 (also reproduces on Linux per type definitions alone)
- Firebase SDK version:
firebase-admin@13.6.0
- Firebase Product: auth
- Node.js version: 22.x
- NPM version: 10.x
[REQUIRED] Step 3: Describe the problem
CreateRequest extends UpdateRequest, so displayName, photoURL, and phoneNumber are typed string | null | undefined on the create path. The runtime, however, only handles null on the update path — updateExistingAccount rewrites displayName: null into deleteAttribute: ['DISPLAY_NAME'] before validation (src/auth/auth-api-request.ts, the deletableParams block). createNewAccount has no such transform, so null flows straight into validateCreateEditRequest, where:
if (typeof request.displayName !== 'undefined' &&
!validator.isString(request.displayName)) {
throw new FirebaseAuthError(AuthClientErrorCode.INVALID_DISPLAY_NAME);
}
isString is typeof v === 'string', so null fails. The type permits a value the runtime always rejects.
The same shape applies to photoURL and phoneNumber on CreateRequest.
Steps to reproduce:
- Compile the snippet below — TypeScript accepts it.
- Run against a real Firebase Auth project (or the emulator).
- Observe
FirebaseAuthError { code: 'auth/invalid-display-name' }.
Relevant Code:
import { getAuth } from 'firebase-admin/auth'
await getAuth().createUser({
uid: 'repro-' + Date.now(),
displayName: null, // typed as string | null, but runtime rejects null
})
// FirebaseAuthError: The displayName field must be a valid string.
// code: 'auth/invalid-display-name'
// Contrast — this works because updateUser rewrites null into deleteAttribute:
await getAuth().updateUser('some-existing-uid', { displayName: null })
Expected
Either:
- Tighten the type: override the inherited members on
CreateRequest to drop | null — i.e. displayName?: string, photoURL?: string, phoneNumber?: string — so the compiler rejects calls the runtime would reject; or
- Relax the runtime: in
createNewAccount, strip null from these fields before validation (on the create path, null has no "clear" semantics — there is no existing value to clear, so null is equivalent to omitted).
Happy to send a PR for whichever direction you prefer.
[READ] Step 1: Are you in the right place?
Yes — bug in the
authcomponent of this repo (typing + runtime divergence betweencreateUserandupdateUser).[REQUIRED] Step 2: Describe your environment
firebase-admin@13.6.0[REQUIRED] Step 3: Describe the problem
CreateRequestextendsUpdateRequest, sodisplayName,photoURL, andphoneNumberare typedstring | null | undefinedon the create path. The runtime, however, only handlesnullon the update path —updateExistingAccountrewritesdisplayName: nullintodeleteAttribute: ['DISPLAY_NAME']before validation (src/auth/auth-api-request.ts, thedeletableParamsblock).createNewAccounthas no such transform, sonullflows straight intovalidateCreateEditRequest, where:isStringistypeof v === 'string', sonullfails. The type permits a value the runtime always rejects.The same shape applies to
photoURLandphoneNumberonCreateRequest.Steps to reproduce:
FirebaseAuthError { code: 'auth/invalid-display-name' }.Relevant Code:
Expected
Either:
CreateRequestto drop| null— i.e.displayName?: string,photoURL?: string,phoneNumber?: string— so the compiler rejects calls the runtime would reject; orcreateNewAccount, stripnullfrom these fields before validation (on the create path,nullhas no "clear" semantics — there is no existing value to clear, sonullis equivalent to omitted).Happy to send a PR for whichever direction you prefer.