{"record":{"id":"70cbd2927da21f70","repo":"Budibase/budibase","slug":"account-holder-cannot-be-deleted","errorCode":null,"errorMessage":"Account holder cannot be deleted","messagePattern":"Account holder cannot be deleted","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/backend-core/src/users/db.ts","lineNumber":577,"sourceCode":"    })\n\n    return response\n  }\n\n  static async destroy(id: string) {\n    const db = getGlobalDB()\n    const dbUser = (await db.get(id)) as User\n    const userId = dbUser._id as string\n\n    if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {\n      // root account holder can't be deleted from inside budibase\n      const email = dbUser.email\n      const account = await accountSdk.getAccount(email)\n      if (account) {\n        if (dbUser.userId === getIdentity()!._id) {\n          throw new HTTPError('Please visit \"Account\" to delete this user', 400)\n        } else {\n          throw new HTTPError(\"Account holder cannot be deleted\", 400)\n        }\n      }\n    }\n\n    await platform.users.removeUser(dbUser)\n\n    await db.remove(userId, dbUser._rev!)\n\n    const creatorsToDelete = (await isCreatorAsync(dbUser)) ? 1 : 0\n    await UserDB.quotas.removeUsers(1, creatorsToDelete)\n    await eventHelpers.handleDeleteEvents(dbUser)\n    await cache.user.invalidateUser(userId)\n    await sessions.invalidateSessions(userId, { reason: \"deletion\" })\n  }\n\n  static async createAdminUser(\n    email: string,\n    tenantId: string,","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/backend-core/src/users/db.ts#L559-L595","documentation":"destroy() throws HTTPError(400) 'Account holder cannot be deleted' when an admin (someone other than the account holder) attempts to delete the tenant's root account-holder user from within the product in a cloud deployment. The account holder record is owned by the account portal and cannot be removed in-app.","triggerScenarios":"destroy() on a user whose email has an account in the account portal, where dbUser.userId differs from the current identity (i.e., an admin deleting the holder), with env.SELF_HOSTED=false and DISABLE_ACCOUNT_PORTAL=false.","commonSituations":"Admins offboarding the original signup user; bulk delete scripts that include the account holder; trying to transfer ownership by deleting and recreating the holder.","solutions":["Remove the account (and its holder) through the Account portal, which handles subscription/tenant teardown","Keep the account-holder user and delete other users only","In self-hosted setups this path is not reachable; ensure SELF_HOSTED/DISABLE_ACCOUNT_PORTAL env flags reflect the real deployment"],"exampleFix":"// before\nawait users.destroy(holderId) // holder, deleted by admin\n// after\n// skip account holders in bulk cleanup\nif (!(await accountSdk.getAccount(user.email))) {\n  await users.destroy(user._id!)\n}","handlingStrategy":"try-catch","validationCode":"// skip account holders in bulk deletion\nconst acct = await accountSdk.getAccount(user.email)\nif (acct && user._id !== getIdentity()?._id) {\n  // this is the account holder being deleted by an admin - not allowed in-product\n}","typeGuard":null,"tryCatchPattern":"try {\n  await users.destroy(userId)\n} catch (e: any) {\n  if (e?.status === 400 && e?.message === \"Account holder cannot be deleted\") {\n    // remove via Account portal or skip this user in bulk jobs\n  } else throw e\n}","preventionTips":["Filter out account holders (users whose email has an account) from bulk delete jobs","Never attempt ownership transfer by delete-and-recreate of the holder","In self-hosted deployments these errors should be unreachable - verify env flags"],"tags":["permissions","account-portal","deletion"],"backgroundTag":"account-holder-deletion-blocked","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}