fullstackhero/dotnet-starter-kit · error · NotFoundException
Brand not found.
Error message
Brand {command.BrandId} not found. What it means
DeleteBrandCommandHandler looks up the brand by command.BrandId and throws NotFoundException when no matching row exists, so the delete is never executed. NotFoundException is mapped to HTTP 404 by the API pipeline. Soft-deleted brands are excluded by the default query filters, so a soft-deleted brand also yields this error.
Solutions
- Verify the BrandId exists via GET /brands/v1/{id} before deleting
- If the brand is soft-deleted, use the Restore endpoint instead of Delete
- Check the tenant header/context matches the tenant that owns the brand
Example fix
// before await mediator.Send(new DeleteBrandCommand(unverifiedId)); // after var brand = await mediator.Send(new GetBrandByIdQuery(id)); // 404 surfaces here first await mediator.Send(new DeleteBrandCommand(brand.Id));
Defensive patterns
Strategy: try-catch
Validate before calling
try { await apiClient.GET($"/brands/v1/{id}"); return true; } catch (HttpRequestException e) when (e.StatusCode == HttpStatusCode.NotFound) { return false; } Try / catch
try { await mediator.Send(new DeleteBrandCommand(id)); }
catch (NotFoundException) { /* treat as already deleted — safe to ignore */ } Prevention
- Refresh entity lists before delete operations in UIs
- Cache brand IDs with invalidation on delete events
- Always send the correct tenant header
When it happens
Trigger: Send/DeleteBrand command with a BrandId that does not exist, was already hard-deleted, or belongs to another tenant.
Common situations: Stale ID cached in a client after the brand was deleted elsewhere; passing a product/category ID by mistake; cross-tenant ID due to a missing tenant header.
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/65a58e65b41cb05c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Brands/DeleteBrand/DeleteBrandCommandHandler.cs:19
using FSH.Framework.Core.Exceptions;
using FSH.Modules.Catalog.Contracts.v1.Brands;
using FSH.Modules.Catalog.Data;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Catalog.Features.v1.Brands.DeleteBrand;
public sealed class DeleteBrandCommandHandler(CatalogDbContext dbContext)
: ICommandHandler<DeleteBrandCommand, Unit>
{
public async ValueTask<Unit> Handle(DeleteBrandCommand command, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(command);
var brand = await dbContext.Brands
.FirstOrDefaultAsync(b => b.Id == command.BrandId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException($"Brand {command.BrandId} not found.");
dbContext.Brands.Remove(brand);
await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
return Unit.Value;
}
}
View on GitHub (pinned to 3f2959e683)