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
- Change the user's role in the upstream identity provider / directory group instead of via this endpoint.
- If manual changes are intentionally allowed, disable externally-managed roles in instance config (consult the access-management runbook first).
- 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 SAML/SCIM/LDAP is enabled, change roles in the directory, not the API.
- Have the UI hide the role-change control when isInstanceRoleManaged() is true.
- Document the externally-managed mode for operators.
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
- Admin cannot reset password of global owner
- Instance owner cannot be deleted.
- Cannot change your own global role
- Admin cannot change role on global owner
- Owner cannot change role on global owner
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/87a95af2d91fa96f.
Report an issue: GitHub.