nopSolutions/nopCommerce · warning · Exception

{ModelState errors joined by ', '}

Error message

{ModelState errors joined by ', '}

What it means

Thrown in EditAddressAsync when ModelState is invalid. The controller collects every ModelState error message, joins them with ', ', and throws a single Exception whose message is that joined string. The surrounding try/catch (line 304) logs it as a warning and returns it to the client as JSON { error = 1, message }. So this is not a server crash but a surfaced validation summary — the message is dynamically composed from the model validation failures.

Source

Thrown at src/Presentation/Nop.Web/Controllers/CheckoutController.cs:277

        if (vatNumberStatus != VatNumberStatus.Valid && !string.IsNullOrEmpty(fullVatNumber))
        {
            var warning = await _localizationService.GetResourceAsync("Checkout.VatNumber.Warning");
            return string.Format(warning, await _localizationService.GetLocalizedEnumAsync(vatNumberStatus));
        }

        return string.Empty;
    }

    protected virtual async Task<JsonResult> EditAddressAsync(AddressModel addressModel, IFormCollection form, Func<Customer, IList<ShoppingCartItem>, Address, Task<JsonResult>> getResult)
    {
        try
        {
            if (!ModelState.IsValid)
            {
                var errors = string.Join(", ", ModelState.Values.Where(p => p.Errors.Any()).SelectMany(p => p.Errors)
                    .Select(p => p.ErrorMessage));

                throw new Exception(errors);
            }

            var customer = await _workContext.GetCurrentCustomerAsync();
            var store = await _storeContext.GetCurrentStoreAsync();
            var cart = await _shoppingCartService.GetShoppingCartAsync(customer, ShoppingCartType.ShoppingCart, store.Id);
            if (!cart.Any())
                throw new Exception("Your cart is empty");

            //find address (ensure that it belongs to the current customer)
            var address = await _customerService.GetCustomerAddressAsync(customer.Id, addressModel.Id)
                          ?? throw new Exception("Address can't be loaded");

            //custom address attributes
            var customAttributes = await _addressAttributeParser.ParseCustomAttributesAsync(form, NopCommonDefaults.AddressAttributeControlName);
            var customAttributeWarnings = await _addressAttributeParser.GetAttributeWarningsAsync(customAttributes);

            if (customAttributeWarnings.Any())
                return Json(new { error = 1, message = customAttributeWarnings });

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Fix the failing address fields per the joined messages shown in the JSON response.
  2. Ensure client-side unobtrusive validation is enabled so invalid posts are prevented before submit.
  3. Review custom AddressModel validation attributes and loosen/fix over-strict rules.
  4. If messages are keys rather than text, verify localization resources are loaded for the address fields.

Example fix

// before
if (!ModelState.IsValid)
{
    var errors = string.Join(", ", ModelState.Values.Where(p => p.Errors.Any()).SelectMany(p => p.Errors)
        .Select(p => p.ErrorMessage));
    throw new Exception(errors);
}
// after (return structured validation JSON)
if (!ModelState.IsValid)
{
    var errors = ModelState.Values.SelectMany(p => p.Errors).Select(p => p.ErrorMessage).ToList();
    return Json(new { error = 1, message = string.Join(", ", errors), fieldErrors = errors });
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate on the client before POST (Razor Pages / MVC unobtrusive validation):
// ensure required address fields (Country, StateProvince, City, ZipPostalCode) are filled.
// Server-side: inspect ModelState without throwing.
if (!ModelState.IsValid)
{
    var errors = ModelState.Values.SelectMany(p => p.Errors).Select(p => p.ErrorMessage).ToList();
    return Json(new { error = 1, message = string.Join(", ", errors) });
}

Try / catch

// Already wrapped: the controller catches Exception and returns JSON.
catch (Exception exc)
{
    await _logger.WarningAsync(exc.Message, exc, await _workContext.GetCurrentCustomerAsync());
    return Json(new { error = 1, message = exc.Message });
}

Prevention

When it happens

Trigger: A billing/shipping address edit POST fails model validation (required fields empty, format violations, attribute constraints). ModelState.Values contains errors; they are concatenated and returned. Common with missing country/zip or invalid email-length rules.

Common situations: Customer submits address form with missing required fields (city, zip, phone); custom address attributes with validation rules fail; localized required-field messages get concatenated; client-side validation bypassed or disabled.

Related errors


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