n8n-io/n8n · error · ForbiddenError
Maximum number of users reached
Error message
Maximum number of users reached
What it means
Thrown by AuthService.issueCookie as a ForbiddenError (RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED) when a non-owner user attempts to log in and the instance has reached its licensed user quota. Owners can still log in to manage the license/seats.
Source
Thrown at packages/cli/src/auth/auth.service.ts:242
}
} catch (e) {
this.logger.warn('failed to invalidate auth token', { error: (e as Error).message });
}
}
issueCookie(
res: Response,
user: User,
usedMfa: boolean,
browserId?: string,
isEmbed?: boolean,
cookieOverrides?: { sameSite?: 'strict' | 'lax' | 'none'; secure?: boolean },
) {
// TODO: move this check to the login endpoint in AuthController
// If the instance has exceeded its user quota, prevent non-owners from logging in
const isWithinUsersLimit = this.license.isWithinUsersLimit();
if (user.role.slug !== GLOBAL_OWNER_ROLE.slug && !isWithinUsersLimit) {
throw new ForbiddenError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
}
const token = this.issueJWT(user, usedMfa, browserId, isEmbed);
const { samesite, secure } = this.globalConfig.auth.cookie;
res.cookie(AUTH_COOKIE_NAME, token, {
maxAge: this.jwtExpiration * Time.seconds.toMilliseconds,
httpOnly: true,
sameSite: cookieOverrides?.sameSite ?? samesite,
secure: cookieOverrides?.secure ?? secure,
});
}
issueJWT(user: User, usedMfa: boolean = false, browserId?: string, isEmbed?: boolean) {
const payload: AuthJwtPayload = {
id: user.id,
hash: this.createJWTHash(user),
browserId: browserId && this.hash(browserId),
usedMfa,View on GitHub (pinned to 5ac6606e81)
Solutions
- An owner logs in and upgrades the license or increases the seat count.
- Deactivate or delete inactive users to free seats (UserManagement), then have the user retry login.
- Verify the license is correctly applied and not expired (n8n logs the license quota at startup).
Example fix
n/a (operational resolution, not a code fix)
Defensive patterns
Strategy: try-catch
Validate before calling
n/a (server-side quota check; client cannot pre-validate licensed seat count)
Type guard
function isQuotaError(error: unknown): boolean {
return error instanceof Error && error.message.includes('Maximum number of users reached');
} Try / catch
// Login flow
try {
await login(email, password);
} catch (e) {
if (isQuotaError(e)) { /* surface 'contact admin to free a seat' to the user */ }
else throw e;
} Prevention
- Monitor licensed seat usage vs. user count as an admin.
- Deactivate offboarded users promptly to free seats.
- Keep the license tier aligned with headcount; renew before expiry.
When it happens
Trigger: A non-owner user submits valid credentials at login (or SSO completes) while the active license's seat count is at or above its limit. The check fires inside issueCookie before a JWT is issued, so no session is created.
Common situations: Community edition limits reached; an expired/downgraded license that shrunk the seat count; offboarded users were not deactivated so seats remain consumed; bulk-provisioned users beyond the licensed tier.
Related errors
- Maximum number of users reached
- Invalid invite URL
- Invalid request
- Maximum number of users reached
- Maximum number of users reached
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/8110df13fb64cf6a.
Report an issue: GitHub.