fullstackhero/dotnet-starter-kit · warning · NotFoundException
Product not found.
Error message
Product {command.ProductId} not found. What it means
AdjustProductStock loads the product by command.ProductId and throws NotFoundException when no product matches. The stock adjustment cannot be applied to a missing aggregate; default soft-delete filters apply.
Solutions
- Verify the product id against the live catalog before adjusting.
- Skip/flag the row and continue batch processing, reporting not-found ids at the end.
- Check whether the product was soft-deleted and restore it.
- Ensure the job runs against the correct database/tenant.
Example fix
// before: fail whole batch on one bad id
foreach (var r in rows) await api.adjustStock(r.productId, r.delta);
// after: tolerate missing products
try { await api.adjustStock(r.productId, r.delta); }
catch (ApiError e) when (e.status === 404) { skipped.push(r.productId); } Defensive patterns
Strategy: try-catch
Validate before calling
const exists = await api.listProducts({ ids: [productId] });
if (!exists.items.length) return skipRow(productId, 'product not found'); Type guard
const isGuid = (v) => typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v); Try / catch
try { await api.adjustStock(productId, delta); }
catch (e) { if (e.status === 404) reportMissing(productId); else throw e; } Prevention
- Re-export id lists immediately before batch inventory runs
- Log and skip missing products instead of aborting the batch
- Confirm the batch job targets the right tenant/database
When it happens
Trigger: POST stock-adjustment for a ProductId that: (1) was deleted, (2) is a wrong Guid, (3) exists in another tenant.
Common situations: Inventory tools batch-adjusting from an exported (stale) id list; product removed by a catalog manager while warehouse staff adjust stock; environment mismatch in scripts.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/d2f9d95faafe9d1c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Products/AdjustProductStock/AdjustProductStockCommandHandler.cs:20
using FSH.Framework.Core.Exceptions;
using FSH.Modules.Catalog.Contracts.v1.Products;
using FSH.Modules.Catalog.Data;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Catalog.Features.v1.Products.AdjustProductStock;
public sealed class AdjustProductStockCommandHandler(CatalogDbContext dbContext)
: ICommandHandler<AdjustProductStockCommand, int>
{
public async ValueTask<int> Handle(AdjustProductStockCommand command, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(command);
var product = await dbContext.Products
.FirstOrDefaultAsync(p => p.Id == command.ProductId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException($"Product {command.ProductId} not found.");
try
{
product.AdjustStock(command.Delta);
}
catch (InvalidOperationException ex)
{
throw new CustomException(ex.Message, (IEnumerable<string>?)null, HttpStatusCode.Conflict);
}
await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
return product.Stock;
}
}
View on GitHub (pinned to 3f2959e683)