{"record":{"id":"f5e557ddbe4b680c","repo":"nextauthjs/next-auth","slug":"no-user-id","errorCode":null,"errorMessage":"No user id.","messagePattern":"No user id\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/adapter-drizzle/src/lib/mysql.ts","lineNumber":213,"sourceCode":"        .then((res) => res[0])\n    },\n    async getSessionAndUser(sessionToken: string) {\n      return client\n        .select({\n          session: sessionsTable,\n          user: usersTable,\n        })\n        .from(sessionsTable)\n        .where(eq(sessionsTable.sessionToken, sessionToken))\n        .innerJoin(usersTable, eq(usersTable.id, sessionsTable.userId))\n        .then((res) => (res.length > 0 ? res[0] : null)) as Awaitable<{\n        session: AdapterSession\n        user: AdapterUser\n      } | null>\n    },\n    async updateUser(data: Partial<AdapterUser> & Pick<AdapterUser, \"id\">) {\n      if (!data.id) {\n        throw new Error(\"No user id.\")\n      }\n\n      await client\n        .update(usersTable)\n        .set(data)\n        .where(eq(usersTable.id, data.id))\n\n      const [result] = await client\n        .select()\n        .from(usersTable)\n        .where(eq(usersTable.id, data.id))\n\n      if (!result) {\n        throw new Error(\"No user found.\")\n      }\n\n      return result as Awaitable<AdapterUser>\n    },","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/adapter-drizzle/src/lib/mysql.ts#L195-L231","documentation":"The MySQL drizzle adapter's updateUser requires data.id to locate the row to update and throws this error when id is missing. updateUser in Auth.js always supplies an id, so this usually means updateUser was called directly with a partial user object lacking id.","triggerScenarios":"Calling adapter.updateUser({ email: 'x' }) without an id property, or id present but undefined due to destructuring/spread of a partial object.","commonSituations":"Custom code calling the adapter directly, building the update object dynamically and dropping id, or integrating with a framework that passes Partial<AdapterUser>.","solutions":["Always include id: adapter.updateUser({ id, ...changes }).","Validate the id exists before calling updateUser.","If updating by email, first getUserByEmail then use the returned user's id."],"exampleFix":"// before\nawait adapter.updateUser({ email: 'new@mail.com' })\n// after\nconst user = await adapter.getUserByEmail('new@mail.com')\nawait adapter.updateUser({ id: user.id, email: 'new@mail.com' })","handlingStrategy":"validation","validationCode":"if (!data.id) throw new Error('updateUser requires an id')","typeGuard":"function hasId(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(data)\n} catch (e) {\n  if (e instanceof Error && e.message === 'No user id.') {\n    // resolve the id via getUserByEmail/getUserByAccount, then retry\n  }\n  throw e\n}","preventionTips":["Never call updateUser without an id in the payload","Resolve ids via getUserByEmail/getUserByAccount when only email/account is known","Type your update payloads as Partial<AdapterUser> & Pick<AdapterUser, 'id'>","Validate inputs at the edge before they reach the adapter"],"tags":["validation","drizzle","mysql","update"],"backgroundTag":"missing-required-field","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}