{"record":{"id":"0b476aa358e4ffa7","repo":"fullstackhero/dotnet-starter-kit","slug":"category-command-categoryid-not-found-0b476a","errorCode":null,"errorMessage":"Category {command.CategoryId} not found.","messagePattern":"Category (.+?) not found\\.","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"warning","filePath":"src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/RestoreCategory/RestoreCategoryCommandHandler.cs","lineNumber":21,"sourceCode":"using FSH.Modules.Catalog.Contracts.v1.Categories;\nusing FSH.Modules.Catalog.Data;\nusing Mediator;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace FSH.Modules.Catalog.Features.v1.Categories.RestoreCategory;\n\npublic sealed class RestoreCategoryCommandHandler(CatalogDbContext dbContext)\n    : ICommandHandler<RestoreCategoryCommand, Guid>\n{\n    public async ValueTask<Guid> Handle(RestoreCategoryCommand command, CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(command);\n\n        var category = await dbContext.Categories\n            .IgnoreQueryFilters([QueryFilters.SoftDelete])\n            .FirstOrDefaultAsync(c => c.Id == command.CategoryId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException($\"Category {command.CategoryId} not found.\");\n\n        category.Restore();\n        await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);\n        return category.Id;\n    }\n}\n","sourceCodeStart":3,"sourceCodeEnd":28,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/RestoreCategory/RestoreCategoryCommandHandler.cs#L3-L28","documentation":"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'.","triggerScenarios":"POST restore for a CategoryId that: (1) was hard-deleted (physically removed), (2) never existed (typo/fabricated Guid), (3) exists only in another tenant.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// ensure the category actually exists (even deleted) before restoring\nconst row = await api.listCategories({ ids: [id], includeDeleted: true });\nif (!row.items.length) return alert('Category no longer exists and cannot be restored');","typeGuard":"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);","tryCatchPattern":"try { await api.restoreCategory(id); }\ncatch (e) { if (e.status === 404) show('Not found — it may have been permanently deleted'); else throw e; }","preventionTips":["Refresh the deleted-items list before restoring","Don't retain hard-deleted ids in client caches","Verify tenant context when restoring from admin tooling"],"tags":["not-found","soft-delete","restore","catalog"],"backgroundTag":"entity-not-found","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}