nopSolutions/nopCommerce · error · Exception
Picture cannot be loaded
Error message
Picture cannot be loaded
What it means
Thrown while preparing the admin product-picture grid (PrepareProductPictureListModel). For each ProductPicture mapping row the factory loads the linked Picture via _pictureService.GetPictureByIdAsync(productPicture.PictureId); if that returns null it throws a bare System.Exception (not NopException), meaning there is no local catch specific to this — it propagates up the request pipeline. It indicates the join table ProductPicture references a PictureId that no longer has a Picture record.
Source
Thrown at src/Presentation/Nop.Web/Areas/Admin/Factories/ProductModelFactory.cs:1589
public virtual async Task<ProductPictureListModel> PrepareProductPictureListModelAsync(ProductPictureSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get product pictures
var productPictures = (await _productService.GetProductPicturesByProductIdAsync(product.Id)).ToPagedList(searchModel);
//prepare grid model
var model = await new ProductPictureListModel().PrepareToGridAsync(searchModel, productPictures, () =>
{
return productPictures.SelectAwait(async productPicture =>
{
//fill in model values from the entity
var productPictureModel = productPicture.ToModel<ProductPictureModel>();
//fill in additional values (not existing in the entity)
var picture = (await _pictureService.GetPictureByIdAsync(productPicture.PictureId))
?? throw new Exception("Picture cannot be loaded");
productPictureModel.PictureUrl = (await _pictureService.GetPictureUrlAsync(picture)).Url;
productPictureModel.OverrideAltAttribute = picture.AltAttribute;
productPictureModel.OverrideTitleAttribute = picture.TitleAttribute;
return productPictureModel;
});
});
return model;
}
/// <summary>
/// Prepare paged product video list model
/// </summary>
/// <param name="searchModel">Product video search model</param>
/// <param name="product">Product</param>View on GitHub (pinned to 64bdf2ff08)
Solutions
- Delete or repair the orphaned ProductPictureMapping rows whose PictureId has no matching Picture row.
- Re-upload the missing picture for the affected product and relink it.
- Run an integrity check: SELECT * FROM Product_Picture_Mapping ppm LEFT JOIN Picture p ON p.Id = ppm.PictureId WHERE p.Id IS NULL; then remove those mappings.
- Restore the Picture table from backup if multiple pictures are missing.
Example fix
// before
var picture = (await _pictureService.GetPictureByIdAsync(productPicture.PictureId))
?? throw new Exception("Picture cannot be loaded");
// after (skip the broken mapping row instead of failing the whole grid)
var picture = await _pictureService.GetPictureByIdAsync(productPicture.PictureId);
if (picture is null)
{
await _logger.WarningAsync($"ProductPicture mapping {productPicture.Id} references missing picture {productPicture.PictureId}");
return null;
} Defensive patterns
Strategy: validation
Validate before calling
// Before rendering the grid, confirm every mapping has a picture.
var productPictures = await _productService.GetProductPicturesByProductIdAsync(product.Id);
var orphans = productPictures.Where(pp => (await _pictureService.GetPictureByIdAsync(pp.PictureId)) is null).ToList();
if (orphans.Any())
await _logger.WarningAsync($"{orphans.Count} product-picture mappings reference missing pictures."); Type guard
static bool PictureResolved(Picture p) => p is not null;
Try / catch
// This throws a bare System.Exception with no local catch in the lambda —
// wrap the grid preparation so a single broken row does not fail the page.
try { /* PrepareToGridAsync body */ }
catch (Exception ex) when (ex.Message == "Picture cannot be loaded")
{
await _logger.WarningAsync(ex.Message, ex);
/* return empty/partial grid */
} Prevention
- Delete ProductPictureMapping rows whenever you delete a Picture record.
- Run an integrity query joining Product_Picture_Mapping to Picture and remove orphans.
- Re-upload missing pictures or prune their mappings during data migration.
When it happens
Trigger: A ProductPictureMapping row has a PictureId for which PictureService.GetPictureByIdAsync returns null. Typically a picture was hard-deleted (or its DB row removed) while the product-picture mapping row was left behind, or a failed picture upload left an orphan mapping.
Common situations: Manual DB cleanup of the Picture table without cleaning ProductPictureMapping; partial import/restore where picture binary rows are missing; storage migration that dropped picture records; concurrent deletion race during image management.
Related errors
- Video cannot be loaded
- No product found with the specified id
- No related product found with the specified id
- No cross-sell product found with the specified id
- No filter level value mapping found with the specified id
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/120613c7002f3f11.
Report an issue: GitHub.