nopSolutions/nopCommerce · error · ArgumentException

No specification attribute found with the specified id

Error message

No specification attribute found with the specified id

What it means

Thrown in PrepareAddSpecificationAttributeModelAsync when editing an existing product specification attribute. The factory loads the attribute by specificationId via GetProductSpecificationAttributeByIdAsync; if null (the id does not match any ProductSpecificationAttribute row) it throws ArgumentException. This typically means the requested specification id was deleted, the URL/query id is stale, or the value was never persisted.

Source

Thrown at src/Presentation/Nop.Web/Areas/Admin/Factories/ProductModelFactory.cs:1733

    {
        if (!specificationId.HasValue)
        {
            return new AddSpecificationAttributeModel
            {
                AvailableAttributes = await (await _specificationAttributeService.GetSpecificationAttributesWithOptionsAsync())
                    .SelectAwait(async attributeWithOption =>
                    {
                        var attributeName = await GetSpecificationAttributeNameAsync(attributeWithOption);

                        return new SelectListItem(attributeName, attributeWithOption.Id.ToString());
                    }).ToListAsync(),
                ProductId = productId,
                Locales = await _localizedModelFactory.PrepareLocalizedModelsAsync<AddSpecificationAttributeLocalizedModel>()
            };
        }

        var attribute = await _specificationAttributeService.GetProductSpecificationAttributeByIdAsync(specificationId.Value)
            ?? throw new ArgumentException("No specification attribute found with the specified id");

        //a vendor should have access only to his products
        var currentVendor = await _workContext.GetCurrentVendorAsync();
        if (currentVendor != null && (await _productService.GetProductByIdAsync(attribute.ProductId)).VendorId != currentVendor.Id)
            throw new UnauthorizedAccessException("This is not your product");

        var specAttributeOption = await _specificationAttributeService.GetSpecificationAttributeOptionByIdAsync(attribute.SpecificationAttributeOptionId);
        var specAttribute = await _specificationAttributeService.GetSpecificationAttributeByIdAsync(specAttributeOption.SpecificationAttributeId);

        var model = attribute.ToModel<AddSpecificationAttributeModel>();
        model.SpecificationId = attribute.Id;
        model.AttributeId = specAttribute.Id;
        model.AttributeTypeName = await _localizationService.GetLocalizedEnumAsync(attribute.AttributeType);
        model.AttributeName = specAttribute.Name;

        model.AvailableAttributes = await (await _specificationAttributeService.GetSpecificationAttributesWithOptionsAsync())
            .SelectAwait(async attributeWithOption =>
            {

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Refresh the product specification list; the attribute no longer exists, so reopen a valid one.
  2. Verify the specificationId in the request corresponds to an existing ProductSpecificationAttribute row.
  3. Add a not-found guard that returns a friendly 'record no longer exists' message instead of an unhandled ArgumentException.
  4. Avoid deep-linking edit popups; always navigate from the current grid.

Example fix

// before
var attribute = await _specificationAttributeService.GetProductSpecificationAttributeByIdAsync(specificationId.Value)
    ?? throw new ArgumentException("No specification attribute found with the specified id");
// after (guard and redirect with message)
var attribute = await _specificationAttributeService.GetProductSpecificationAttributeByIdAsync(specificationId.Value);
if (attribute is null)
{
    _notificationService.ErrorNotification("The specification attribute no longer exists.");
    return RedirectToRoute(/* product spec list */);
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the specification id before loading the editor.
var attribute = await _specificationAttributeService.GetProductSpecificationAttributeByIdAsync(specificationId.Value);
if (attribute is null)
{
    _notificationService.ErrorNotification("This specification attribute no longer exists.");
    return; // or redirect to the list
}

Type guard

static bool SpecAttributeExists(ProductSpecificationAttribute a) => a is not null;

Try / catch

try { /* PrepareAddSpecificationAttributeModelAsync body */ }
catch (ArgumentException ex) when (ex.Message.Contains("specification attribute"))
{
    _notificationService.ErrorNotification(ex.Message);
}

Prevention

When it happens

Trigger: An admin request to edit a product specification attribute supplies a specificationId that resolves to no ProductSpecificationAttribute row. Triggered by following a stale edit link, deleting the attribute in another tab, or a malformed/guessed id.

Common situations: Concurrent admin edits where one user deletes the attribute while another opens its editor; bookmarked edit URLs after the attribute was removed; a bad/templated id passed from a custom integration; race between load and edit.

Related errors


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