nopSolutions/nopCommerce · warning · NopException

The system name of system customer roles can't be edited.

Error message

The system name of system customer roles can't be edited.

What it means

Thrown in the CustomerRole Edit action when a system role's SystemName is being changed (a case-insensitive comparison between the persisted SystemName and the posted model.SystemName fails). System names are programmatic identifiers referenced throughout nopCommerce code via constants (e.g. NopCustomerDefaults.RegisteredRoleName), so renaming them would break role resolution. It is a NopException shown as an error notification.

Source

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

    [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");
            }

            //prepare model

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Do not modify the SystemName field for any role flagged IsSystemRole — it is read-only by contract.
  2. If a different identifier is needed, create a new non-system role.
  3. Check import/migration scripts to ensure they never overwrite SystemName on system roles.
  4. Verify the posted model.SystemName exactly matches the stored value for system roles.

Example fix

// before — model.SystemName edited for a system role -> NopException

// after — render SystemName read-only in the view for system roles
@if (Model.IsSystemRole)
{
    @Html.DisplayFor(model => model.SystemName)
}
else
{
    @Html.EditorFor(model => model.SystemName)
}
Defensive patterns

Strategy: validation

Validate before calling

// Before saving: reject SystemName change for system roles
var role = await _customerService.GetCustomerRoleByIdAsync(model.Id);
if (role?.IsSystemRole == true && !role.SystemName.Equals(model.SystemName, StringComparison.OrdinalIgnoreCase))
{
    ModelState.AddModelError("SystemName", "System role system names cannot be changed.");
    return View(model);
}

Type guard

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

Try / catch

// Existing try/catch renders the localized error notification; keep input consistent to avoid it.

Prevention

When it happens

Trigger: POST to CustomerRole/Edit where the role is a system role and the model.SystemName differs (case-insensitively) from the existing customerRole.SystemName.

Common situations: An admin edits the 'System name' text box for a built-in role; a config import/seed overrides SystemName for a system role; localization confusion leads someone to 'translate' the system name.

Related errors


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