nextauthjs/next-auth · error
No user id.
Error message
No user id.
What it means
The Drizzle PostgreSQL adapter's updateUser requires a user id to build its WHERE clause. If the AdapterUser passed in has no id (falsy/undefined), the adapter refuses to issue an UPDATE that would otherwise match every row, and throws this error instead. It is a defensive input-validation guard inside packages/adapter-drizzle/src/lib/pg.ts updateUser.
Source
Thrown at packages/adapter-drizzle/src/lib/pg.ts:193
.then((res) => res[0])
},
async getSessionAndUser(sessionToken: string) {
return client
.select({
session: sessionsTable,
user: usersTable,
})
.from(sessionsTable)
.where(eq(sessionsTable.sessionToken, sessionToken))
.innerJoin(usersTable, eq(usersTable.id, sessionsTable.userId))
.then((res) => (res.length > 0 ? res[0] : null)) as Awaitable<{
session: AdapterSession
user: AdapterUser
} | null>
},
async updateUser(data: Partial<AdapterUser> & Pick<AdapterUser, "id">) {
if (!data.id) {
throw new Error("No user id.")
}
const [result] = await client
.update(usersTable)
.set(data)
.where(eq(usersTable.id, data.id))
.returning()
if (!result) {
throw new Error("No user found.")
}
return result as Awaitable<AdapterUser>
},
async updateSession(
data: Partial<AdapterSession> & Pick<AdapterSession, "sessionToken">
) {
return clientView on GitHub (pinned to a1a16a5a77)
Solutions
- Ensure the object passed to updateUser includes a valid id: updateUser({ id: user.id, name: 'New Name' }).
- Check that the user object originates from getUser/getUserByAccount/getUserByEmail so the id is populated by the adapter.
- Add an early check in your code: if (!user.id) throw new Error('id required') before calling updateUser.
- If id exists but is falsy at runtime, verify your custom users table id column mapping in the Drizzle schema (e.g. uuid default).
Example fix
// before
await adapter.updateUser({ name: 'Alice' })
// after
await adapter.updateUser({ id: existingUser.id, name: 'Alice' }) Defensive patterns
Strategy: validation
Validate before calling
if (!user || !user.id) throw new Error('updateUser requires a valid user.id')
await adapter.updateUser({ id: user.id, ...patch }) Type guard
function hasId(u: Partial<AdapterUser> | undefined | null): u is AdapterUser & { id: string } {
return typeof u?.id === 'string' && u.id.length > 0
} Try / catch
try {
await adapter.updateUser(patch)
} catch (e) {
if ((e as Error).message === 'No user id.') {
throw new Error('Caller bug: user id missing before updateUser')
}
throw e
} Prevention
- Always source user objects from adapter getters (getUser/getUserByEmail) so id is populated.
- Type update payloads as AdapterUser & Partial<AdapterUser> rather than Partial<AdapterUser> alone.
- Add a runtime assertion helper for ids before any adapter write.
When it happens
Trigger: Calling updateUser({}) or updateUser({ name: 'x' }) without an id property, or with id: undefined / id: '' — typically from a custom flow that builds the partial user manually instead of receiving it from Auth.js.
Common situations: Custom user-migration or admin scripts that construct AdapterUser objects by hand; spreading an object whose id field was renamed (e.g. userId instead of id); typing the argument loosely as Partial<AdapterUser> so TS doesn't catch the missing id at compile time.
Related errors
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/b35180f03a8ed60a.
Report an issue: GitHub.