nextauthjs/next-auth · error

Error updating user: Failed to run the update SQL.

Error message

Error updating user: Failed to run the update SQL.

What it means

updateUser only re-fetches and returns a user when the UPDATE result reports success; if D1 does not report success (or the params shape is missing), the adapter falls through to this error. It means the UPDATE statement itself failed at the driver/batch level rather than returning zero rows.

Source

Thrown at packages/adapter-d1/src/index.ts:218

        Object.assign(params, user)
        const res = await updateRecord(db, UPDATE_USER_BY_ID_SQL, [
          params.name,
          params.email,
          params.emailVerified?.toISOString(),
          params.image,
          params.id,
        ])
        if (res.success) {
          const user = await getRecord<AdapterUser>(db, GET_USER_BY_ID_SQL, [
            params.id,
          ])
          if (user) return user
          throw new Error(
            "Error updating user: Cannot get user after updating."
          )
        }
      }
      throw new Error("Error updating user: Failed to run the update SQL.")
    },
    async deleteUser(userId) {
      // miniflare doesn't support batch operations or multiline sql statements
      await deleteRecord(db, DELETE_ACCOUNT_BY_USER_ID_SQL, [userId])
      await deleteRecord(db, DELETE_SESSION_BY_USER_ID_SQL, [userId])
      await deleteRecord(db, DELETE_USER_SQL, [userId])
      return null
    },
    async linkAccount(a) {
      // convert user_id to userId and provider_account_id to providerAccountId
      const id = crypto.randomUUID()
      const createBindings = [
        id,
        a.userId,
        a.type,
        a.provider,
        a.providerAccountId,
        a.refresh_token,

View on GitHub (pinned to a1a16a5a77)

Solutions

  1. Log/inspect the thrown driver error underneath and confirm the SQL update statement matches your users table columns.
  2. Ensure params.id is a valid existing user id and the params object only contains AdapterUser fields.
  3. Run against real D1 or a current miniflare version — old miniflare builds don't support batch operations.
  4. Update @auth/d1-adapter to the latest version.

Example fix

// before
await adapter.updateUser({ ...user, name: 'new' }) // extra fields may break SQL
// after
await adapter.updateUser({ id: user.id, name: 'new' })
Defensive patterns

Strategy: try-catch

Validate before calling

if (!params?.id) throw new Error('updateUser requires a valid user id')
const existing = await adapter.getUser(params.id)
if (!existing) throw new Error('user does not exist')

Type guard

function isValidUpdateParams(p: unknown): p is Partial<AdapterUser> & Pick<AdapterUser, 'id'> {
  return !!p && typeof p === 'object' && typeof (p as any).id === 'string'
}

Try / catch

try {
  await adapter.updateUser(params)
} catch (e) {
  if (e instanceof Error && e.message.includes('Failed to run the update SQL')) {
    // log the driver error, verify table schema/columns, check D1 status
  }
  throw e
}

Prevention

When it happens

Trigger: adapter.updateUser(params) where the D1 batch result's success flag is false — malformed SQL, wrong binding types, D1 API errors, or params lacking a valid id so the generated UPDATE is invalid.

Common situations: Passing an AdapterUser whose extra fields don't match table columns, D1 outages/rate limits, older adapter versions generating SQL incompatible with current D1, or miniflare lacking batch support (see the comment in deleteUser).

Related errors


AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28). Data as JSON: /api/errors/3ffa760b21038fff. Report an issue: GitHub.