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

  1. An owner logs in and upgrades the license or increases the seat count.
  2. Deactivate or delete inactive users to free seats (UserManagement), then have the user retry login.
  3. 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

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


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/8110df13fb64cf6a. Report an issue: GitHub.