{"record":{"id":"fe98dce51b8afdc7","repo":"n8n-io/n8n","slug":"cannot-invite-admin-user-without-advanced-permissi","errorCode":null,"errorMessage":"Cannot invite admin user without advanced permissions. Please upgrade to a license that includes this feature.","messagePattern":"Cannot invite admin user without advanced permissions\\. Please upgrade to a license that includes this feature\\.","errorType":"exception","errorClass":"ForbiddenError","httpStatus":403,"severity":"warning","filePath":"packages/cli/src/controllers/invitation.controller.ts","lineNumber":78,"sourceCode":"\t\t}\n\n\t\tif (!isWithinUsersLimit) {\n\t\t\tthis.logger.debug(\n\t\t\t\t'Request to send email invite(s) to user(s) failed because the user limit quota has been reached',\n\t\t\t);\n\t\t\tthrow new ForbiddenError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);\n\t\t}\n\n\t\tif (!(await this.ownershipService.hasInstanceOwner())) {\n\t\t\tthis.logger.debug(\n\t\t\t\t'Request to send email invite(s) to user(s) failed because the owner account is not set up',\n\t\t\t);\n\t\t\tthrow new BadRequestError('You must set up your own account before inviting others');\n\t\t}\n\n\t\tconst attributes = invitations.map(({ email, role }) => {\n\t\t\tif (role === 'global:admin' && !this.license.isAdvancedPermissionsLicensed()) {\n\t\t\t\tthrow new ForbiddenError(\n\t\t\t\t\t'Cannot invite admin user without advanced permissions. Please upgrade to a license that includes this feature.',\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn { email, role };\n\t\t});\n\n\t\tconst { usersInvited, usersCreated } = await this.userService.inviteUsers(req.user, attributes);\n\n\t\tawait this.externalHooks.run('user.invited', [usersCreated]);\n\n\t\treturn usersInvited;\n\t}\n\n\t/**\n\t * Process invitation acceptance: validate users, update invitee, and handle authentication.\n\t */\n\tprivate async processInvitationAcceptance(\n\t\tinviterId: string,","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/controllers/invitation.controller.ts#L60-L96","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Upgrade to a license that includes advanced permissions before inviting admins.","Change the invite role to 'global:member' or another role allowed by the current license.","Verify the license entitlement via GET /license or the Admin UI > License before retrying."],"exampleFix":"// before\nawait api.post('/invite', [{ email, role: 'global:admin' }]);\n\n// after: downgrade role when license lacks advanced permissions\nconst role = license.hasAdvancedPermissions ? 'global:admin' : 'global:member';\nawait api.post('/invite', [{ email, role }]);","handlingStrategy":"validation","validationCode":"// Check advanced-permissions entitlement before inviting an admin.\nconst license = await api.get('/license');\nconst canInviteAdmin = license.features.includes('feat:advancedPermissions');\nconst role = canInviteAdmin ? 'global:admin' : 'global:member';","typeGuard":"function canInviteAdminRole(license: { features: string[] }): boolean {\n  return license.features.includes('feat:advancedPermissions');\n}","tryCatchPattern":"try {\n  await api.post('/invite', [{ email, role: 'global:admin' }]);\n} catch (e) {\n  if (e.response?.status === 403 && /advanced permissions/i.test(e.response.data.message)) {\n    // downgrade role or prompt upgrade\n    await api.post('/invite', [{ email, role: 'global:member' }]);\n    return;\n  }\n  throw e;\n}","preventionTips":["Query license entitlements before offering the admin role in the invite UI.","Disable the admin-role dropdown when advanced permissions are absent.","Plan license tier to match the number of admins needed."],"tags":["invitations","license","rbac","admin","forbidden"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}