{"record":{"id":"bcd7b4ec3afc5ac2","repo":"fullstackhero/dotnet-starter-kit","slug":"category-query-categoryid-not-found","errorCode":null,"errorMessage":"Category {query.CategoryId} not found.","messagePattern":"Category (.+?) not found\\.","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"warning","filePath":"src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/GetCategoryById/GetCategoryByIdQueryHandler.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.GetCategoryById;\n\npublic sealed class GetCategoryByIdQueryHandler(CatalogDbContext dbContext)\n    : IQueryHandler<GetCategoryByIdQuery, CategoryDto>\n{\n    public async ValueTask<CategoryDto> Handle(GetCategoryByIdQuery query, CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(query);\n\n        var c = await dbContext.Categories\n            .AsNoTracking()\n            .FirstOrDefaultAsync(c => c.Id == query.CategoryId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException($\"Category {query.CategoryId} not found.\");\n\n        return new CategoryDto(c.Id, c.Name, c.Slug, c.Description, c.ParentCategoryId, c.CreatedAtUtc, c.UpdatedAtUtc, c.DeletedOnUtc, c.DeletedBy);\n    }\n}\n","sourceCodeStart":3,"sourceCodeEnd":26,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/GetCategoryById/GetCategoryByIdQueryHandler.cs#L3-L26","documentation":"GetCategoryById throws NotFoundException when no category with the requested CategoryId exists in the Categories table. The lookup uses AsNoTracking with the default query filters, so soft-deleted categories are also filtered out and produce the same 'not found' result. It is a normal 404-style outcome, not a bug.","triggerScenarios":"GET category by id where: (1) the Guid is wrong or from another environment, (2) the category was soft-deleted (DeletedOnUtc set, filtered by the SoftDelete query filter), (3) the category belongs to a different tenant than the request's tenant context.","commonSituations":"Stale UI links/bookmarks to a deleted category; copying ids between dev/staging/prod databases; multi-tenant apps where the id exists in another tenant; tests seeding one database but querying another.","solutions":["Verify the CategoryId Guid is correct and exists: SELECT * FROM \"Categories\" WHERE \"Id\" = '<id>'.","Check whether the row is soft-deleted (DeletedOnUtc IS NOT NULL) and restore it if needed.","Confirm the request is made against the intended tenant so the global query filter matches the row.","Ensure the client is pointed at the right environment/database connection string."],"exampleFix":"// before (client assumes category always exists)\nvar category = await api.getCategory(id);\nrender(category);\n\n// after\nvar category = await api.getCategory(id); // throws NotFound -> handled\nif (category is null) { show(\"Category no longer exists\"); return; }","handlingStrategy":"try-catch","validationCode":"// client-side pre-check before deep-linking\nif (!/^[0-9a-f-]{36}$/i.test(categoryId)) return reject('invalid category id');\nconst exists = await api.listCategories({ ids: [categoryId] });\nif (!exists.items.length) return show('Category not found');","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 { const c = await api.getCategory(id); render(c); }\ncatch (e) { if (e.status === 404) show('Category not found or deleted'); else throw e; }","preventionTips":["Refetch ids from the API instead of persisting them in long-lived links","Don't reuse ids across environments","Show soft-deleted categories as disabled rather than 404 in listings"],"tags":["not-found","catalog","categories","ef-core"],"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"}