nopSolutions/nopCommerce · error · ArgumentException

No product tag found with the specified id

Error message

No product tag found with the specified id

What it means

Thrown by ProductTagDelete when _productTagService.GetProductTagByIdAsync(id) returns null. Product tags are global catalog entities (no vendor ownership check here). The endpoint deletes a tag by id from the product-tags grid.

Source

Thrown at src/Presentation/Nop.Web/Areas/Admin/Controllers/ProductController.cs:2687

    }

    [HttpPost]
    [CheckPermission(StandardPermission.Catalog.PRODUCT_TAGS_VIEW)]
    public virtual async Task<IActionResult> ProductTags(ProductTagSearchModel searchModel)
    {
        //prepare model
        var model = await _productModelFactory.PrepareProductTagListModelAsync(searchModel);

        return Json(model);
    }

    [HttpPost]
    [CheckPermission(StandardPermission.Catalog.PRODUCT_TAGS_CREATE_EDIT_DELETE)]
    public virtual async Task<IActionResult> ProductTagDelete(int id)
    {
        //try to get a product tag with the specified id
        var tag = await _productTagService.GetProductTagByIdAsync(id)
            ?? throw new ArgumentException("No product tag found with the specified id");

        await _productTagService.DeleteProductTagAsync(tag);

        _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Catalog.ProductTags.Deleted"));

        return RedirectToAction("ProductTags");
    }

    [HttpPost]
    [CheckPermission(StandardPermission.Catalog.PRODUCT_TAGS_CREATE_EDIT_DELETE)]
    public virtual async Task<IActionResult> ProductTagsDelete(ICollection<int> selectedIds)
    {
        if (selectedIds == null || !selectedIds.Any())
            return NoContent();

        var tags = await _productTagService.GetProductTagsByIdsAsync(selectedIds.ToArray());
        await _productTagService.DeleteProductTagsAsync(tags);

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Make the delete idempotent: if the tag is gone, redirect to ProductTags without error.
  2. Refresh the tags grid after any delete or bulk delete.
  3. Disable the delete control until the AJAX response resolves.
  4. Replace the throw with a null guard returning a notification/redirect.

Example fix

// before
var tag = await _productTagService.GetProductTagByIdAsync(id)
    ?? throw new ArgumentException("No product tag found with the specified id");
await _productTagService.DeleteProductTagAsync(tag);

// after
var tag = await _productTagService.GetProductTagByIdAsync(id);
if (tag == null)
{
    _notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Catalog.ProductTags.NotExist"));
    return RedirectToAction("ProductTags");
}
await _productTagService.DeleteProductTagAsync(tag);
Defensive patterns

Strategy: validation

Validate before calling

var tag = await _productTagService.GetProductTagByIdAsync(id);
if (tag == null)
{
    _notificationService.ErrorNotification("Tag no longer exists.");
    return RedirectToAction("ProductTags");
}

Try / catch

try { /* delete tag */ }
catch (ArgumentException ex) when (ex.Message.Contains("product tag"))
    return RedirectToAction("ProductTags");

Prevention

When it happens

Trigger: POST Admin/Product/ProductTagDelete?id=... for a tag already deleted (double delete), or a grid row stale after a prior delete or a ProductTagsDelete bulk action that already removed it.

Common situations: Double-click delete. Bulk ProductTagsDelete followed by an individual delete on the same id from a stale grid. Two admins managing tags concurrently.

Related errors


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