fullstackhero/dotnet-starter-kit · warning · NotFoundException
Category not found.
Error message
Category {command.CategoryId} not found. What it means
UpdateCategory throws NotFoundException when no category with command.CategoryId exists (default soft-delete filter applies, so soft-deleted categories also hit this). The update cannot proceed without an existing aggregate to mutate.
Solutions
- Reload the category list and retry the update with a current id.
- Verify the id exists and is not soft-deleted in the target database.
- Handle the NotFoundException in the client by showing 'category was deleted'.
- Check tenant headers/context are correct.
Example fix
// before: blind update
await api.updateCategory({ id: staleId, name: 'New Name' });
// after: refetch first
const cat = await api.getCategory(id); // throws NotFound -> prompt user Defensive patterns
Strategy: try-catch
Validate before calling
const cat = await api.getCategory(id).catch(() => null);
if (!cat) return prompt('Category was deleted; reload before editing'); Try / catch
try { await api.updateCategory(payload); }
catch (e) { if (e.status === 404) { reloadList(); show('Category no longer exists'); } else throw e; } Prevention
- Reload entity data before opening the edit form
- Use optimistic-concurrency hints so deletions surface early
- Avoid hardcoded ids in scripts
When it happens
Trigger: PUT/PATCH update for a CategoryId that: (1) was deleted before the update arrived, (2) is a wrong/typo Guid, (3) lives in another tenant.
Common situations: Two users editing concurrently — one deletes while the other saves; stale list page submitting updates for removed categories; automated scripts with hardcoded ids.
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/b1fbafe22d1a1a6e.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/UpdateCategory/UpdateCategoryCommandHandler.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.UpdateCategory;
public sealed class UpdateCategoryCommandHandler(CatalogDbContext dbContext)
: ICommandHandler<UpdateCategoryCommand, Guid>
{
public async ValueTask<Guid> Handle(UpdateCategoryCommand 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.");
if (command.ParentCategoryId is { } parentId)
{
if (parentId == category.Id)
{
throw new CustomException(
"A category cannot be its own parent.",
(IEnumerable<string>?)null,
HttpStatusCode.BadRequest);
}
// Walk parent chain to detect cycles (parent → ancestor of self)
var visited = new HashSet<Guid> { category.Id };
Guid? cursor = parentId;
while (cursor is { } cur)
{
if (!visited.Add(cur))
{View on GitHub (pinned to 3f2959e683)