nextauthjs/next-auth · error
No user found.
Error message
No user found.
What it means
After issuing UPDATE ... WHERE id = ? RETURNING on the users table, the Drizzle pg adapter checks the returned row. If no row came back, the UPDATE matched zero rows — meaning no user with that id exists — and the adapter throws 'No user found.' rather than silently returning undefined.
Source
Thrown at packages/adapter-drizzle/src/lib/pg.ts:203
.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 client
.update(sessionsTable)
.set(data)
.where(eq(sessionsTable.sessionToken, data.sessionToken))
.returning()
.then((res) => res[0])
},
async linkAccount(data: AdapterAccount) {
await client.insert(accountsTable).values(data)
},
async getUserByAccount(View on GitHub (pinned to a1a16a5a77)
Solutions
- Verify the user with getUser(id) exists before calling updateUser.
- Confirm the adapter's Drizzle client points at the same database/schema where the user row lives (check connection string per environment).
- Check whether the row was deleted by another process/job; refresh the id from the source of truth.
- Inspect the usersTable schema mapping to make sure eq(usersTable.id, data.id) compares the right column/type.
Example fix
// before
await adapter.updateUser({ id: maybeId, email: newEmail })
// after
const user = await adapter.getUser(maybeId)
if (!user) throw new Error(`User ${maybeId} does not exist`)
await adapter.updateUser({ id: user.id, email: newEmail }) Defensive patterns
Strategy: validation
Validate before calling
const existing = await adapter.getUser(id)
if (!existing) throw new Error(`Cannot update: no user with id ${id}`)
await adapter.updateUser({ id, ...patch }) Type guard
function isExistingUser(u: AdapterUser | null): u is AdapterUser {
return u !== null && typeof u.id === 'string'
} Try / catch
try {
await adapter.updateUser({ id, ...patch })
} catch (e) {
if ((e as Error).message === 'No user found.') {
console.warn(`User ${id} not found; skipping update`)
return null
}
throw e
} Prevention
- Read-before-write: call getUser(id) and bail out when null.
- Keep ids in sync across environments; never hardcode ids from another database.
- Watch for concurrent delete jobs that may remove users between read and update.
When it happens
Trigger: Calling updateUser({ id: '<nonexistent-id>' , ...changes }) where the id is not present in the users table (row deleted concurrently, wrong database, stale id from a client).
Common situations: Stale ids held in a client after the user was deleted in another session; pointing the adapter at a different database/env than the one that created the user; soft-delete setups that remove rows the adapter still expects; id type mismatches (string uuid vs integer) that silently match nothing.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/8cd133046c649ef6.
Report an issue: GitHub.