{"record":{"id":"b1fbafe22d1a1a6e","repo":"fullstackhero/dotnet-starter-kit","slug":"category-command-categoryid-not-found-b1fbaf","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/UpdateCategory/UpdateCategoryCommandHandler.cs","lineNumber":20,"sourceCode":"using FSH.Framework.Core.Exceptions;\nusing FSH.Modules.Catalog.Contracts.v1.Categories;\nusing FSH.Modules.Catalog.Data;\nusing Mediator;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace FSH.Modules.Catalog.Features.v1.Categories.UpdateCategory;\n\npublic sealed class UpdateCategoryCommandHandler(CatalogDbContext dbContext)\n    : ICommandHandler<UpdateCategoryCommand, Guid>\n{\n    public async ValueTask<Guid> Handle(UpdateCategoryCommand command, CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(command);\n\n        var category = await dbContext.Categories\n            .FirstOrDefaultAsync(c => c.Id == command.CategoryId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException($\"Category {command.CategoryId} not found.\");\n\n        if (command.ParentCategoryId is { } parentId)\n        {\n            if (parentId == category.Id)\n            {\n                throw new CustomException(\n                    \"A category cannot be its own parent.\",\n                    (IEnumerable<string>?)null,\n                    HttpStatusCode.BadRequest);\n            }\n\n            // Walk parent chain to detect cycles (parent → ancestor of self)\n            var visited = new HashSet<Guid> { category.Id };\n            Guid? cursor = parentId;\n            while (cursor is { } cur)\n            {\n                if (!visited.Add(cur))\n                {","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/UpdateCategory/UpdateCategoryCommandHandler.cs#L2-L38","documentation":"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.","triggerScenarios":"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.","commonSituations":"Two users editing concurrently — one deletes while the other saves; stale list page submitting updates for removed categories; automated scripts with hardcoded ids.","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."],"exampleFix":"// before: blind update\nawait api.updateCategory({ id: staleId, name: 'New Name' });\n\n// after: refetch first\nconst cat = await api.getCategory(id); // throws NotFound -> prompt user","handlingStrategy":"try-catch","validationCode":"const cat = await api.getCategory(id).catch(() => null);\nif (!cat) return prompt('Category was deleted; reload before editing');","typeGuard":null,"tryCatchPattern":"try { await api.updateCategory(payload); }\ncatch (e) { if (e.status === 404) { reloadList(); show('Category no longer exists'); } else throw e; }","preventionTips":["Reload entity data before opening the edit form","Use optimistic-concurrency hints so deletions surface early","Avoid hardcoded ids in scripts"],"tags":["not-found","update","catalog","concurrency"],"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"}