Budibase/budibase · error · EmailUnavailableError
Email already in use: '${email}'
Error message
Email already in use: '${email}' What it means
validateUniqueUser throws EmailUnavailableError when multi-tenancy is enabled and the requested email already belongs to a platform user in a DIFFERENT tenant. This prevents cross-tenant email collisions and user hijacking in shared-platform deployments.
Source
Thrown at packages/backend-core/src/users/utils.ts:71
groups?: UserGroup[]
) {
const userGroups = groups?.filter(
group => user.userGroups?.indexOf(group._id!) !== -1
)
if (userGroups && userGroups.length > 0) {
return userGroups.some(group =>
Object.values(group.roles || {}).includes("CREATOR")
)
}
return false
}
export async function validateUniqueUser(email: string, tenantId: string) {
// check budibase users in other tenants
if (env.MULTI_TENANCY) {
const tenantUser = await getFirstPlatformUser(email)
if (tenantUser != null && tenantUser.tenantId !== tenantId) {
throw new EmailUnavailableError(email)
}
}
// check root account users in account portal
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
const account = await accountSdk.getAccount(email)
if (account && account.verified && account.tenantId !== tenantId) {
throw new EmailUnavailableError(email)
}
}
}
/**
* For a list of users, return the account holder if there is an email match.
*/
export async function getAccountHolderFromUsers(
users: Array<UserIdentifier>
): Promise<UserIdentifier | undefined> {View on GitHub (pinned to a81a902e9a)
Solutions
- Use a different email address for the new tenant user
- Delete/deactivate the user in the other tenant first (via that tenant's admin or the account portal)
- Verify MULTI_TENANCY is intentionally true for your deployment; on single-tenant self-host, set it false
- If the user legitimately migrated tenants, update their platform user's tenantId rather than re-inviting
Example fix
// before
await validateUniqueUser("shared@example.com", "tenantB") // exists in tenantA
// after
const existing = await getFirstPlatformUser("shared@example.com")
if (existing && existing.tenantId !== "tenantB") {
email = "shared-tenantB@example.com" // pick an unclaimed email
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check cross-tenant usage under multi-tenancy
if (env.MULTI_TENANCY) {
const u = await getFirstPlatformUser(email)
if (u && u.tenantId !== currentTenantId) throw new Error("Email used in another tenant")
} Try / catch
import { EmailUnavailableError } from "@budibase/backend-core"
try {
await validateUniqueUser(email, tenantId)
} catch (e) {
if (e instanceof EmailUnavailableError) {
// prompt for a different email or handle tenant migration
} else throw e
} Prevention
- Under MULTI_TENANCY, expect globally unique emails and validate invites up front
- Confirm MULTI_TENANCY matches your real deployment topology
- For tenant migration, update the platform user's tenantId rather than re-inviting
When it happens
Trigger: save() -> validateUniqueUser(email, tenantId) with env.MULTI_TENANCY=true and getFirstPlatformUser(email) returning a user whose tenantId differs from the caller's tenant - typically when creating a new user or changing a user's email.
Common situations: Inviting a user who signed up under another tenant in Budibase Cloud; moving users between tenants; self-hosted installations mistakenly run with MULTI_TENANCY=true; typos reusing a colleague's email already registered elsewhere.
Related errors
- Email already in use: '${email}'
- Group name "${name}" is unavailable
- Link token is not valid for this workspace
- OAuth2 config with name '${name}' is already taken.
- A custom REST template named "${name.trim()}" already exists
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/20e483033efcc16b.
Report an issue: GitHub.