nextauthjs/next-auth · error

User not found.

Error message

User not found.

What it means

The SQLite Drizzle adapter's updateUser runs UPDATE ... WHERE id = ? RETURNING().get(). If .get() returns undefined, the WHERE clause matched no row, so the user with that id does not exist and the adapter throws 'User not found.'

Source

Thrown at packages/adapter-drizzle/src/lib/sqlite.ts:204

      return result 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()
        .get()

      if (!result) {
        throw new Error("User not found.")
      }

      return result as Awaitable<AdapterUser>
    },
    async updateSession(
      data: Partial<AdapterSession> & Pick<AdapterSession, "sessionToken">
    ) {
      const result = await client
        .update(sessionsTable)
        .set(data)
        .where(eq(sessionsTable.sessionToken, data.sessionToken))
        .returning()
        .get()

      return result ?? null
    },
    async linkAccount(data: AdapterAccount) {
      await client.insert(accountsTable).values(data).run()

View on GitHub (pinned to a1a16a5a77)

Solutions

  1. Call getUser(id) first and only update when the user exists.
  2. Confirm the Drizzle SQLite client uses the expected database file (check the db filename/connection per environment).
  3. Ensure the id value's type matches how it was stored (consistent string uuids recommended).
  4. If users are being deleted elsewhere, handle the not-found case in your flow instead of blindly updating.

Example fix

// before
await adapter.updateUser({ id: staleId, name: 'New' })
// after
const user = await adapter.getUser(staleId)
if (!user) {
  console.warn('User vanished, skipping update', staleId)
  return
}
await adapter.updateUser({ id: user.id, name: 'New' })
Defensive patterns

Strategy: validation

Validate before calling

const existing = await adapter.getUser(id)
if (!existing) throw new Error(`No SQLite user with id ${id}`)
await adapter.updateUser({ id, ...patch })

Try / catch

try {
  await adapter.updateUser({ id, ...patch })
} catch (e) {
  if ((e as Error).message === 'User not found.') {
    console.warn(`User ${id} missing in SQLite; skipping update`)
    return null
  }
  throw e
}

Prevention

When it happens

Trigger: updateUser({ id: someId, ... }) where no row in the SQLite users table has that id — deleted user, wrong DB file, or id type mismatch (e.g. number vs string in SQLite).

Common situations: SQLite file path differences between environments (dev db vs test db) so the id exists in one but not the other; resetting the database file while holding stale session/user ids; SQLite flexible-mode type affinity causing '1' vs 1 id mismatches.

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/5da50ac8b981aafe. Report an issue: GitHub.