fullstackhero/dotnet-starter-kit · warning · NotFoundException
Category not found.
Error message
Category {command.CategoryId} not found. What it means
RestoreCategory looks the category up with IgnoreQueryFilters([QueryFilters.SoftDelete]) so soft-deleted rows are visible, but still throws NotFoundException when no row with the given CategoryId exists at all — including rows hard-deleted or never created. This means 'not even in the recycle bin'.
Solutions
- Check the row exists physically: SELECT * FROM "Categories" WHERE "Id" = '<id>' — if absent, it cannot be restored.
- Re-fetch the category list from the API instead of using a stale client-side id.
- Verify tenant context matches the row's tenant.
- If the row was purged, recreate the category rather than restoring.
Defensive patterns
Strategy: validation
Validate before calling
// ensure the category actually exists (even deleted) before restoring
const row = await api.listCategories({ ids: [id], includeDeleted: true });
if (!row.items.length) return alert('Category no longer exists and cannot be restored'); 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.restoreCategory(id); }
catch (e) { if (e.status === 404) show('Not found — it may have been permanently deleted'); else throw e; } Prevention
- Refresh the deleted-items list before restoring
- Don't retain hard-deleted ids in client caches
- Verify tenant context when restoring from admin tooling
When it happens
Trigger: POST restore for a CategoryId that: (1) was hard-deleted (physically removed), (2) never existed (typo/fabricated Guid), (3) exists only in another tenant.
Common situations: Retrying a restore after the row was permanently purged by a cleanup job; client caching a stale id of a hard-deleted category; ids copied between environments.
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/0b476aa358e4ffa7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/RestoreCategory/RestoreCategoryCommandHandler.cs:21
using FSH.Modules.Catalog.Contracts.v1.Categories;
using FSH.Modules.Catalog.Data;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Catalog.Features.v1.Categories.RestoreCategory;
public sealed class RestoreCategoryCommandHandler(CatalogDbContext dbContext)
: ICommandHandler<RestoreCategoryCommand, Guid>
{
public async ValueTask<Guid> Handle(RestoreCategoryCommand command, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(command);
var category = await dbContext.Categories
.IgnoreQueryFilters([QueryFilters.SoftDelete])
.FirstOrDefaultAsync(c => c.Id == command.CategoryId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException($"Category {command.CategoryId} not found.");
category.Restore();
await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
return category.Id;
}
}
View on GitHub (pinned to 3f2959e683)