{"record":{"id":"120613c7002f3f11","repo":"nopSolutions/nopCommerce","slug":"picture-cannot-be-loaded-120613","errorCode":null,"errorMessage":"Picture cannot be loaded","messagePattern":"Picture cannot be loaded","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/Presentation/Nop.Web/Areas/Admin/Factories/ProductModelFactory.cs","lineNumber":1589,"sourceCode":"    public virtual async Task<ProductPictureListModel> PrepareProductPictureListModelAsync(ProductPictureSearchModel searchModel, Product product)\n    {\n        ArgumentNullException.ThrowIfNull(searchModel);\n        ArgumentNullException.ThrowIfNull(product);\n\n        //get product pictures\n        var productPictures = (await _productService.GetProductPicturesByProductIdAsync(product.Id)).ToPagedList(searchModel);\n\n        //prepare grid model\n        var model = await new ProductPictureListModel().PrepareToGridAsync(searchModel, productPictures, () =>\n        {\n            return productPictures.SelectAwait(async productPicture =>\n            {\n                //fill in model values from the entity\n                var productPictureModel = productPicture.ToModel<ProductPictureModel>();\n\n                //fill in additional values (not existing in the entity)\n                var picture = (await _pictureService.GetPictureByIdAsync(productPicture.PictureId))\n                    ?? throw new Exception(\"Picture cannot be loaded\");\n\n                productPictureModel.PictureUrl = (await _pictureService.GetPictureUrlAsync(picture)).Url;\n\n                productPictureModel.OverrideAltAttribute = picture.AltAttribute;\n                productPictureModel.OverrideTitleAttribute = picture.TitleAttribute;\n\n                return productPictureModel;\n            });\n        });\n\n        return model;\n    }\n\n    /// <summary>\n    /// Prepare paged product video list model\n    /// </summary>\n    /// <param name=\"searchModel\">Product video search model</param>\n    /// <param name=\"product\">Product</param>","sourceCodeStart":1571,"sourceCodeEnd":1607,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Presentation/Nop.Web/Areas/Admin/Factories/ProductModelFactory.cs#L1571-L1607","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvar picture = (await _pictureService.GetPictureByIdAsync(productPicture.PictureId))\n    ?? throw new Exception(\"Picture cannot be loaded\");\n// after (skip the broken mapping row instead of failing the whole grid)\nvar picture = await _pictureService.GetPictureByIdAsync(productPicture.PictureId);\nif (picture is null)\n{\n    await _logger.WarningAsync($\"ProductPicture mapping {productPicture.Id} references missing picture {productPicture.PictureId}\");\n    return null;\n}","handlingStrategy":"validation","validationCode":"// Before rendering the grid, confirm every mapping has a picture.\nvar productPictures = await _productService.GetProductPicturesByProductIdAsync(product.Id);\nvar orphans = productPictures.Where(pp => (await _pictureService.GetPictureByIdAsync(pp.PictureId)) is null).ToList();\nif (orphans.Any())\n    await _logger.WarningAsync($\"{orphans.Count} product-picture mappings reference missing pictures.\");","typeGuard":"static bool PictureResolved(Picture p) => p is not null;","tryCatchPattern":"// This throws a bare System.Exception with no local catch in the lambda —\n// wrap the grid preparation so a single broken row does not fail the page.\ntry { /* PrepareToGridAsync body */ }\ncatch (Exception ex) when (ex.Message == \"Picture cannot be loaded\")\n{\n    await _logger.WarningAsync(ex.Message, ex);\n    /* return empty/partial grid */\n}","preventionTips":["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."],"tags":["nopcommerce","admin","product","picture","orphan-reference","data-integrity"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}