fullstackhero/dotnet-starter-kit · error · NotFoundException
Category not found.
Error message
Category {command.CategoryId} not found. What it means
DeleteCategoryCommandHandler loads the category by command.CategoryId and throws NotFoundException (HTTP 404) when no row matches, so the delete never runs. Soft-deleted and cross-tenant rows are excluded by the default query filters.
Solutions
- Confirm the CategoryId exists via the categories endpoint
- Refresh the list and retry with a valid ID
- Check tenant context if the category exists in another tenant
Defensive patterns
Strategy: try-catch
Validate before calling
try { await mediator.Send(new GetCategoryByIdQuery(id)); return true; }
catch (NotFoundException) { return false; } Try / catch
try { await mediator.Send(new DeleteCategoryCommand(id)); }
catch (NotFoundException) { /* already deleted — no-op */ } Prevention
- Refresh tree data before deletes
- Make deletes idempotent (swallow 404)
- Verify tenant header on cross-environment testing
When it happens
Trigger: Send/DeleteCategory command with a CategoryId that does not exist, was already deleted, or belongs to another tenant.
Common situations: Deleting from a stale grid after another user removed the category; wrong tenant header; passing a brand/product ID by mistake.
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/67113e1f55bf50d5.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/DeleteCategory/DeleteCategoryCommandHandler.cs:20
using FSH.Framework.Core.Exceptions;
using FSH.Modules.Catalog.Contracts.v1.Categories;
using FSH.Modules.Catalog.Data;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Catalog.Features.v1.Categories.DeleteCategory;
public sealed class DeleteCategoryCommandHandler(CatalogDbContext dbContext)
: ICommandHandler<DeleteCategoryCommand, Unit>
{
public async ValueTask<Unit> Handle(DeleteCategoryCommand command, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(command);
var category = await dbContext.Categories
.FirstOrDefaultAsync(c => c.Id == command.CategoryId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException($"Category {command.CategoryId} not found.");
bool hasChildren = await dbContext.Categories
.AnyAsync(c => c.ParentCategoryId == category.Id, cancellationToken)
.ConfigureAwait(false);
if (hasChildren)
{
throw new CustomException(
"Cannot delete a category that has child categories. Move or remove the children first.",
(IEnumerable<string>?)null,
HttpStatusCode.Conflict);
}
dbContext.Categories.Remove(category);
await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
return Unit.Value;
}
}
View on GitHub (pinned to 3f2959e683)