n8n-io/n8n · error · ForbiddenError

Instance roles are managed automatically and cannot be chang

Error message

Instance roles are managed automatically and cannot be changed manually

What it means

Returned by PATCH /users/:id/role (scope user:changeRole, license feat:advancedPermissions) when provisioningService.isInstanceRoleManaged() resolves true — meaning role assignment is driven by an external provisioning system (SAML/LDAP/SCIM). In that mode, manual role changes from the UI/API are forbidden to avoid drift. HTTP 403.

Source

Thrown at packages/cli/src/controllers/users.controller.ts:348

			migrationUserId: transfereeId,
		});

		await this.externalHooks.run('user.deleted', [await this.userService.toPublic(userToDelete)]);

		return { success: true };
	}

	@Patch('/:id/role')
	@GlobalScope('user:changeRole')
	@Licensed('feat:advancedPermissions')
	async changeGlobalRole(
		req: AuthenticatedRequest,
		_: Response,
		@Body payload: RoleChangeRequestDto,
		@Param('id') id: string,
	) {
		if (await this.provisioningService.isInstanceRoleManaged()) {
			throw new ForbiddenError(
				'Instance roles are managed automatically and cannot be changed manually',
			);
		}

		const { NO_ADMIN_ON_OWNER, NO_USER, NO_OWNER_ON_OWNER, CANNOT_CHANGE_OWN_ROLE } =
			UsersController.ERROR_MESSAGES.CHANGE_ROLE;

		if (req.user.id === id) {
			throw new ForbiddenError(CANNOT_CHANGE_OWN_ROLE);
		}

		const targetUser = await this.userRepository.findOne({
			where: { id },
			relations: ['role'],
		});
		if (targetUser === null) {
			throw new NotFoundError(NO_USER);
		}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Change the user's role in the upstream identity provider / directory group instead of via this endpoint.
  2. If manual changes are intentionally allowed, disable externally-managed roles in instance config (consult the access-management runbook first).
  3. Have the UI hide the role-change control when isInstanceRoleManaged() is true.
Defensive patterns

Strategy: validation

Validate before calling

async function isInstanceRoleManaged() {
  const r = await fetch('/rest/settings', { headers: authHeaders() });
  const s = await r.json();
  return Boolean(s.data?.externalIdentityProviderEnabled || s.data?.samlEnabled || s.data?.ldapEnabled);
}
if (await isInstanceRoleManaged()) {
  throw new Error('Roles are managed by the identity provider; change them there');
}

Try / catch

try { await fetch(`/rest/users/${id}/role`, { method: 'PATCH', body: JSON.stringify(payload) }); }
catch (e) { if (e.statusCode === 403 && /managed automatically/.test(e.message)) { /* route to IdP */ } else throw e; }

Prevention

When it happens

Trigger: Any PATCH /users/:id/role call while the instance is configured for externally-managed roles (SAML JIT, LDAP sync, SCIM). The check runs before any per-user logic.

Common situations: Enterprise deployment with SAML/SCIM where directory groups map to n8n roles; an admin tries the legacy 'change role' button that the UI failed to hide when managed mode is on.

Related errors


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