n8n-io/n8n · error · ForbiddenError
Maximum number of users reached
Error message
Maximum number of users reached
What it means
ForbiddenError (HTTP 403) thrown from auth.controller.ts:235 when resolving a signup invitation token while the instance license reports the active user count is already at the entitlement ceiling. `RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED` is the literal 'Maximum number of users reached'. The license check (`this.license.isWithinUsersLimit()`) runs on every invitation-link resolve, so even an already-issued invite becomes unresolvable once a later signup filled the last seat.
Source
Thrown at packages/cli/src/controllers/auth.controller.ts:235
}
if (!payload.token) {
this.logger.debug('Request to resolve signup token failed because token is missing');
throw new BadRequestError('Token is required');
}
const { inviterId, inviteeId } = await this.userService.getInvitationIdsFromPayload(
payload.token,
);
const isWithinUsersLimit = this.license.isWithinUsersLimit();
if (!isWithinUsersLimit) {
this.logger.debug('Request to resolve signup token failed because of users quota reached', {
inviterId,
inviteeId,
});
throw new ForbiddenError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
}
const users = await this.userRepository.findManyByIds([inviterId, inviteeId], {
includeRole: true,
});
if (users.length !== 2) {
this.logger.debug(
'Request to resolve signup token failed because the ID of the inviter and/or the ID of the invitee were not found in database',
{ inviterId, inviteeId },
);
throw new BadRequestError('Invalid invite URL');
}
const invitee = users.find((user) => user.id === inviteeId);
if (!invitee || invitee.password) {
this.logger.error('Invalid invite URL - invitee already setup', {
inviterId,View on GitHub (pinned to 5ac6606e81)
Solutions
- Raise the seat entitlement: upgrade the license / add seats in the billing console, then reactivate via `n8n license:info` and re-resolve the same invite URL.
- Free a seat: deactivate or delete an unused user in Settings > Users, confirm the count drops, then re-open the invite link.
- Re-issue the invitation after the seat change so the resolve runs against an in-limit state.
- If unexpected, audit actual user count (`SELECT COUNT(*) FROM user`) against the license entitlement — orphaned/inactive users still consume seats.
Example fix
// before — invite resolves against a saturated instance GET /resolve-signup-token?token=... // 403 Maximum number of users reached // after — free a seat, then re-resolve DELETE /users/<inactive-user-id> // admin frees the seat GET /resolve-signup-token?token=... // succeeds
Defensive patterns
Strategy: validation
Validate before calling
// Before mailing/reusing an invite, check license headroom
import { Service } from '@n8n/di';
// in an admin client
async function canInvite(license: LicenseService, userService: UserService) {
const activeUsers = await userService.count(); // your repo method
return license.isWithinUsersLimit() && activeUsers < license.userLimit;
}
// only re-share the invite URL when canInvite(...) returns true Try / catch
// fetch invite resolve
try {
await fetch('/resolve-signup-token?token=' + tok);
} catch (e) {
if (e.status === 403 && /quota|maximum/i.test(e.message)) {
// surface 'request more seats' to the admin instead of retrying
}
} Prevention
- Monitor active-user count vs license entitlement with an alert before the limit is hit.
- Revoke pending invites when headcount drops, so stale links don't resolve against a saturated license.
- Provision license seat bumps before mailing new invites.
When it happens
Trigger: A GET/POST to the signup-invite resolve endpoint with a valid token whose `inviterId`/`inviteeId` decode successfully, but the license's current seat usage equals the entitlement. Reproducible by inviting user N+1 after the Nth user already claimed a seat, or by an admin deleting and re-issuing an invite after headcount grew.
Common situations: Self-hosted instances on a fixed-seat Enterprise/Pro plan that onboarded up to the limit; trial licenses expiring mid-onboarding; stale invite links mailed before a hiring freeze hit. Cloud-managed instances rarely hit this because seat enforcement is upstream.
Related errors
- Maximum number of users reached
- Invalid invite URL
- The invitation was likely either deleted or already claimed
- Invalid request
- Maximum number of users reached
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/6e55a1ad813e591d.
Report an issue: GitHub.