n8n-io/n8n · warning · ForbiddenError

Cannot invite admin user without advanced permissions. Pleas

Error message

Cannot invite admin user without advanced permissions. Please upgrade to a license that includes this feature.

What it means

A ForbiddenError (HTTP 403) thrown inside the invitations.map() when a requested role is 'global:admin' but this.license.isAdvancedPermissionsLicensed() returns false. Admin-level invitations require the advanced-permissions license feature; without it the request is rejected even if seats remain. It is a license-gate, not a validation error, so it returns 403.

Source

Thrown at packages/cli/src/controllers/invitation.controller.ts:78

		}

		if (!isWithinUsersLimit) {
			this.logger.debug(
				'Request to send email invite(s) to user(s) failed because the user limit quota has been reached',
			);
			throw new ForbiddenError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
		}

		if (!(await this.ownershipService.hasInstanceOwner())) {
			this.logger.debug(
				'Request to send email invite(s) to user(s) failed because the owner account is not set up',
			);
			throw new BadRequestError('You must set up your own account before inviting others');
		}

		const attributes = invitations.map(({ email, role }) => {
			if (role === 'global:admin' && !this.license.isAdvancedPermissionsLicensed()) {
				throw new ForbiddenError(
					'Cannot invite admin user without advanced permissions. Please upgrade to a license that includes this feature.',
				);
			}
			return { email, role };
		});

		const { usersInvited, usersCreated } = await this.userService.inviteUsers(req.user, attributes);

		await this.externalHooks.run('user.invited', [usersCreated]);

		return usersInvited;
	}

	/**
	 * Process invitation acceptance: validate users, update invitee, and handle authentication.
	 */
	private async processInvitationAcceptance(
		inviterId: string,

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Upgrade to a license that includes advanced permissions before inviting admins.
  2. Change the invite role to 'global:member' or another role allowed by the current license.
  3. Verify the license entitlement via GET /license or the Admin UI > License before retrying.

Example fix

// before
await api.post('/invite', [{ email, role: 'global:admin' }]);

// after: downgrade role when license lacks advanced permissions
const role = license.hasAdvancedPermissions ? 'global:admin' : 'global:member';
await api.post('/invite', [{ email, role }]);
Defensive patterns

Strategy: validation

Validate before calling

// Check advanced-permissions entitlement before inviting an admin.
const license = await api.get('/license');
const canInviteAdmin = license.features.includes('feat:advancedPermissions');
const role = canInviteAdmin ? 'global:admin' : 'global:member';

Type guard

function canInviteAdminRole(license: { features: string[] }): boolean {
  return license.features.includes('feat:advancedPermissions');
}

Try / catch

try {
  await api.post('/invite', [{ email, role: 'global:admin' }]);
} catch (e) {
  if (e.response?.status === 403 && /advanced permissions/i.test(e.response.data.message)) {
    // downgrade role or prompt upgrade
    await api.post('/invite', [{ email, role: 'global:member' }]);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /invite with one or more entries whose role is 'global:admin' on an instance whose license does not include advanced permissions (e.g. Starter or a community-licensed install). The check fires per-invite during the attributes mapping, after owner and quota checks pass.

Common situations: Downgrading a license from Enterprise to a lower tier that drops advanced permissions; inviting an admin on a trial that expired; scripting invites with role: 'global:admin' against a non-licensed instance.

Related errors


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