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

  1. Verify the user with getUser(id) exists before calling updateUser.
  2. Confirm the adapter's Drizzle client points at the same database/schema where the user row lives (check connection string per environment).
  3. Check whether the row was deleted by another process/job; refresh the id from the source of truth.
  4. 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

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.