{"record":{"id":"f4dfef99a3fce395","repo":"fullstackhero/dotnet-starter-kit","slug":"system-role-permissions-are-managed-by-the-framework-and","errorCode":null,"errorMessage":"System role permissions are managed by the framework and cannot be modified.","messagePattern":"System role permissions are managed by the framework and cannot be modified\\.","errorType":"exception","errorClass":"CustomException","httpStatus":400,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs","lineNumber":188,"sourceCode":"        EnsureNotSystemRole(role.Name, \"System role permissions are managed by the framework and cannot be modified.\");\n        FilterRootPermissions(permissions);\n\n        var currentClaims = await roleManager.GetClaimsAsync(role);\n        await RemoveRevokedPermissionsAsync(role, currentClaims, permissions, cancellationToken);\n        await AddNewPermissionsAsync(role, currentClaims, permissions, cancellationToken);\n\n        // Permissions on the role just changed — every user reachable through this\n        // role (directly or via group membership) now has a stale cache entry.\n        await InvalidateAffectedUsersAsync(roleId, cancellationToken).ConfigureAwait(false);\n\n        return \"permissions updated\";\n    }\n\n    private static void EnsureNotSystemRole(string? roleName, string message)\n    {\n        if (!string.IsNullOrEmpty(roleName) && RoleConstants.IsDefault(roleName))\n        {\n            throw new CustomException(message, Array.Empty<string>(), HttpStatusCode.BadRequest);\n        }\n    }\n\n    private void FilterRootPermissions(List<string> permissions)\n    {\n        if (multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id == MultitenancyConstants.Root.Id)\n        {\n            // The root operator may manage root-only permissions.\n            return;\n        }\n\n        // Strip every permission flagged IsRoot in the registry. (A prior prefix check on \"Permissions.Root.\"\n        // was a no-op — no root perm uses that prefix — letting a tenant admin grant themselves root perms.)\n        var rootOnly = PermissionConstants.Root.Select(p => p.Name).ToHashSet(StringComparer.Ordinal);\n        permissions.RemoveAll(rootOnly.Contains);\n    }\n\n    private async Task RemoveRevokedPermissionsAsync(FshRole role, IList<System.Security.Claims.Claim> currentClaims, List<string> permissions, CancellationToken cancellationToken = default)","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs#L170-L206","documentation":"EnsureNotSystemRole throws CustomException with HTTP 400 when the target role's name matches RoleConstants.IsDefault — i.e. a built-in framework role (like Basic/Admin) whose definition is managed by the framework.","triggerScenarios":"CreateOrUpdateRoleAsync renaming a default role, DeleteRoleAsync deleting one, or UpdatePermissionsAsync mutating the permissions of a default role.","commonSituations":"Trying to tune down the built-in Admin role's permissions; seeding code that modifies stock roles; renaming 'Basic' for branding.","solutions":["Create a custom role with the desired name/permissions instead of editing the default one","Remove default roles from editable lists in the UI (mark as system)","If truly needed, change RoleConstants/seed data — not via the API"],"exampleFix":"// before\nawait roleService.UpdatePermissionsAsync(basicRoleId, limitedPerms, ct);\n// after\nvar customRoleId = await roleService.CreateOrUpdateRoleAsync(null, \"Limited\", \"Custom limited role\", ct);\nawait roleService.UpdatePermissionsAsync(customRoleId, limitedPerms, ct);","handlingStrategy":"validation","validationCode":"var role = await roleService.GetRoleAsync(roleId, ct);\nif (role is not null && RoleConstants.IsDefault(role.Name))\n    throw new InvalidOperationException($\"{role.Name} is a system role and cannot be modified\");","typeGuard":"public static bool IsSystemRole(RoleDto? r) => r is not null && RoleConstants.IsDefault(r.Name);","tryCatchPattern":"try { await roleService.UpdatePermissionsAsync(roleId, perms, ct); }\ncatch (CustomException ex) when (ex.Message.Contains(\"System role\")) { return Results.BadRequest(ex.Message); }","preventionTips":["Maintain a client-side allowlist of editable roles","Hide delete/rename actions for roles flagged as system","Never re-purpose default roles for custom permission sets"],"tags":["identity","roles","system-role","validation"],"backgroundTag":"permission-denied","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}