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 modelView on GitHub (pinned to 64bdf2ff08)
Solutions
- Do not modify the SystemName field for any role flagged IsSystemRole — it is read-only by contract.
- If a different identifier is needed, create a new non-system role.
- Check import/migration scripts to ensure they never overwrite SystemName on system roles.
- 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
- Make the SystemName field read-only for system roles in the UI.
- Never overwrite SystemName in migration/seed scripts for built-in roles.
- Treat SystemName as a programmatic constant, not a display label.
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
- System customer roles can't be disabled.
- You cannot specify "Purchased with product" value for "Regis
- You cannot delete this email account. At least one account i
- Country '{shippingCountry.Name}' is not allowed for shipping
- Checkout.MinOrderSubtotalAmount
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/ddcc1b175644f051.
Report an issue: GitHub.