Budibase/budibase · error
Unable to create new user, invitation invalid.
Error message
Unable to create new user, invitation invalid.
What it means
The worker's invite-users handler catches errors thrown while creating users/invitations and re-throws them as a 400, preferring the underlying error message and only falling back to 'Unable to create new user, invitation invalid.' if none exists. This generic fallback appears when the failure produced no message at all. It signals the invite or user-creation step failed (duplicate email, quota exceeded re-thrown above this branch, DB error, etc.).
Source
Thrown at packages/worker/src/api/controllers/global/users.ts:776
expires: new Date(0),
})
ctx.body = {
_id: user._id!,
_rev: user._rev!,
email: user.email,
tenantId: user.tenantId,
}
}
)
} catch (err: any) {
if (err.code === APIWarningCode.USAGE_LIMIT_EXCEEDED) {
// explicitly re-throw limit exceeded errors
ctx.throw(400, err?.message || err)
}
console.warn("Error inviting user", err)
ctx.throw(
400,
err?.message || err || "Unable to create new user, invitation invalid."
)
}
}
export const addUserToWorkspace = async (
ctx: UserCtx<
EditUserPermissionsResponse,
SaveUserResponse,
{ userId: string; role: string }
>
) => handleUserWorkspacePermission(ctx, ctx.params.userId, ctx.params.role)
export const removeUserFromWorkspace = async (
ctx: UserCtx<
EditUserPermissionsResponse,
SaveUserResponse,
{ userId: string }View on GitHub (pinned to a81a902e9a)
Solutions
- Inspect worker logs for 'Error inviting user' to get the real underlying error object.
- Validate the invite payload: emails are valid addresses and rows are not duplicated within the batch.
- Retry after confirming the invite cache and CouchDB are healthy.
- If a usage limit was actually hit, the endpoint returns the specific USAGE_LIMIT_EXCEEDED message instead — check billing/plan limits separately.
Example fix
// before: posting rows with empty email strings
await api.post('/api/global/users/invite', rows)
// after: filter invalid rows client-side first
const valid = rows.filter(r => /^[^@]+@[^@]+\.[^@]+$/.test(r.email))
await api.post('/api/global/users/invite', valid) Defensive patterns
Strategy: validation
Validate before calling
const valid = invites.filter(i => /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(i.email))
if (valid.length === 0) throw new Error("No valid emails to invite") Type guard
const isInvitable = (u: unknown): u is { email: string } =>
typeof u === "object" && u !== null && "email" in u && typeof (u as { email: unknown }).email === "string" Try / catch
try {
await api.inviteUsers(invites)
} catch (e) {
// prefer e.message; fallback is generic invite failure
console.error(e?.message || "Unable to create new user, invitation invalid.")
} Prevention
- Validate emails client-side before batching invites
- Deduplicate rows in bulk/CSV imports
- Check plan usage limits before large invite batches
- Verify cache/CouchDB health when invites fail repeatedly
When it happens
Trigger: POST to the invite users endpoint where userSdk.invite throws a non-usage-limit error with no message, e.g. invitation cache write fails, payload malformed so err?.message and err are both falsy after handling.
Common situations: Bulk CSV import containing rows that all fail validation leaving an empty error; invite storage (CouchDB/Redis) unavailable; tenant user quota checks throwing empty errors; stale client SDKs posting a legacy payload shape.
Related errors
- No user ID provided for getting
- Unable to delete self.
- There was a problem with the invite
- OIDC Config contents invalid
- User ID missing
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/d4e47f8efc74ea55.
Report an issue: GitHub.