nopSolutions/nopCommerce · warning · NopException

System customer roles can't be disabled.

Error message

System customer roles can't be disabled.

What it means

Thrown inside the CustomerRole Edit action when a role with IsSystemRole == true is being saved with Active == false. System roles (e.g. Administrators, Registered, Guests, ForumModerators, Vendors) are foundational to the platform's authorization and must always remain active. It is a NopException thrown inside a try/catch that renders an error notification and re-displays the edit view.

Source

Thrown at src/Presentation/Nop.Web/Areas/Admin/Controllers/CustomerRoleController.cs:148

        return View(model);
    }

    [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
    [CheckPermission(StandardPermission.Customers.CUSTOMER_ROLES_CREATE_EDIT_DELETE)]
    [CheckPermission(StandardPermission.Configuration.MANAGE_ACL)]
    public virtual async Task<IActionResult> Edit(CustomerRoleModel model, bool continueEditing)
    {
        //try to get a customer role with the specified id
        var customerRole = await _customerService.GetCustomerRoleByIdAsync(model.Id);
        if (customerRole == null)
            return RedirectToAction("List");

        try
        {
            if (ModelState.IsValid)
            {
                if (customerRole.IsSystemRole && !model.Active)
                    throw new NopException(await _localizationService.GetResourceAsync("Admin.Customers.CustomerRoles.Fields.Active.CantEditSystem"));

                if (customerRole.IsSystemRole && !customerRole.SystemName.Equals(model.SystemName, StringComparison.InvariantCultureIgnoreCase))
                    throw new NopException(await _localizationService.GetResourceAsync("Admin.Customers.CustomerRoles.Fields.SystemName.CantEditSystem"));

                if (NopCustomerDefaults.RegisteredRoleName.Equals(customerRole.SystemName, StringComparison.InvariantCultureIgnoreCase) &&
                    model.PurchasedWithProductId > 0)
                    throw new NopException(await _localizationService.GetResourceAsync("Admin.Customers.CustomerRoles.Fields.PurchasedWithProduct.Registered"));

                customerRole = model.ToEntity(customerRole);
                await _customerService.UpdateCustomerRoleAsync(customerRole);

                //activity log
                await _customerActivityService.InsertActivityAsync("EditCustomerRole",
                    string.Format(await _localizationService.GetResourceAsync("ActivityLog.EditCustomerRole"), customerRole.Name), customerRole);

                _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.CustomerRoles.Updated"));

                return continueEditing ? RedirectToAction("Edit", new { id = customerRole.Id }) : RedirectToAction("List");

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Leave 'Is active' checked for any role whose IsSystemRole flag is true (the edit form marks these).
  2. If you truly need a role disabled, create a new non-system role instead of modifying the built-in one.
  3. Audit any automation/bulk scripts to skip system roles before flipping the Active flag.
  4. Inspect the role's IsSystemRole value in the admin UI and do not toggle Active for it.

Example fix

// before — submits system role with Active=false -> NopException

// after — keep system role active; disable logic only for non-system roles
if (model.Active == false && customerRole.IsSystemRole)
{
    _notificationService.WarningNotification("System roles cannot be disabled.");
    return View(model);
}
Defensive patterns

Strategy: validation

Validate before calling

// Before saving: skip system roles when toggling Active
if (model.Active == false)
{
    var role = await _customerService.GetCustomerRoleByIdAsync(model.Id);
    if (role?.IsSystemRole == true)
    {
        ModelState.AddModelError("Active", "System roles cannot be disabled.");
        return View(model);
    }
}

Type guard

bool CanToggleActive(CustomerRole role) => !role?.IsSystemRole ?? false;

Try / catch

// The action already wraps in try/catch and renders ErrorNotification — rely on it and correct input.

Prevention

When it happens

Trigger: POST to CustomerRole/Edit with a model whose Id resolves to a system role and Active is unchecked (false) in the 'Is active' field.

Common situations: An admin mistakenly tries to disable a built-in role; a bulk role-management script toggles all roles inactive; importing role configuration that does not special-case system roles.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/06cd3da71e2059d8. Report an issue: GitHub.