{"record":{"id":"87ceef077161e13e","repo":"nextauthjs/next-auth","slug":"updateuser-missing-id","errorCode":null,"errorMessage":"[updateUser] Missing id","messagePattern":"\\[updateUser\\] Missing id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/adapter-firebase/src/index.ts","lineNumber":129,"sourceCode":"    },\n\n    async getUserByEmail(email) {\n      return await getOneDoc(C.users.where(\"email\", \"==\", email))\n    },\n\n    async getUserByAccount({ provider, providerAccountId }) {\n      const account = await getOneDoc(\n        C.accounts\n          .where(\"provider\", \"==\", provider)\n          .where(mapper.toDb(\"providerAccountId\"), \"==\", providerAccountId)\n      )\n      if (!account) return null\n\n      return await getDoc(C.users.doc(account.userId))\n    },\n\n    async updateUser(partialUser) {\n      if (!partialUser.id) throw new Error(\"[updateUser] Missing id\")\n\n      const userRef = C.users.doc(partialUser.id)\n\n      await userRef.set(partialUser, { merge: true })\n\n      const user = await getDoc(userRef)\n      if (!user) throw new Error(\"[updateUser] Failed to fetch updated user\")\n\n      return user\n    },\n\n    async deleteUser(userId) {\n      await db.runTransaction(async (transaction) => {\n        const accounts = await C.accounts\n          .where(mapper.toDb(\"userId\"), \"==\", userId)\n          .get()\n        const sessions = await C.sessions\n          .where(mapper.toDb(\"userId\"), \"==\", userId)","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/adapter-firebase/src/index.ts#L111-L147","documentation":"The Firebase adapter's updateUser requires the incoming partial user to carry an id, because the id is needed to resolve the Firestore document reference (C.users.doc(id)). Without it there is nothing to merge into, so it throws '[updateUser] Missing id'.","triggerScenarios":"Calling updateUser({ email: '...' }) or updateUser({ id: undefined, ... }) — usually when code spreads a payload whose id was stripped, or when upstream Auth.js events pass a user object that lost its id.","commonSituations":"Custom JWT/session callbacks that rebuild the user object and omit id; mapping between Firestore document field 'userId' and AdapterUser 'id'; API handlers accepting client JSON that lacks the id field.","solutions":["Always include the document id: updateUser({ id: user.id, ...patch }).","Resolve the id first via getUserByEmail or getUserByAccount when you only have the email/account.","Validate incoming payloads in API routes to require id before invoking updateUser.","Check any mapping layer (Firestore doc -> AdapterUser) preserves the id field."],"exampleFix":"// before\nawait adapter.updateUser({ name: 'Alice' })\n// after\nconst existing = await adapter.getUserByEmail('alice@example.com')\nawait adapter.updateUser({ id: existing.id, name: 'Alice' })","handlingStrategy":"validation","validationCode":"if (!partialUser?.id) throw new Error('updateUser requires partialUser.id')\nawait adapter.updateUser(partialUser)","typeGuard":"function isUserWithId(u: Partial<AdapterUser>): u is Partial<AdapterUser> & Pick<AdapterUser, 'id'> {\n  return typeof u.id === 'string' && u.id.length > 0\n}","tryCatchPattern":"try {\n  await adapter.updateUser(partialUser)\n} catch (e) {\n  if ((e as Error).message === '[updateUser] Missing id') {\n    const existing = await adapter.getUserByEmail(partialUser.email!)\n    if (existing) return adapter.updateUser({ ...partialUser, id: existing.id })\n  }\n  throw e\n}","preventionTips":["Resolve ids via getUserByEmail/getUserByAccount before partial updates.","Validate API payloads with a schema (zod) requiring id for update endpoints.","Keep the Firestore id mapped to AdapterUser.id in any custom mappers."],"tags":["input-validation","firebase","firestore"],"backgroundTag":"missing-entity-id","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}