{"record":{"id":"fd8b3aaa679485c0","repo":"fullstackhero/dotnet-starter-kit","slug":"brand-command-brandid-not-found-updatebrandcommandhandler","errorCode":null,"errorMessage":"Brand {command.BrandId} not found.","messagePattern":"Brand (.+?) not found\\.","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Catalog/Modules.Catalog/Features/v1/Brands/UpdateBrand/UpdateBrandCommandHandler.cs","lineNumber":20,"sourceCode":"using FSH.Framework.Core.Exceptions;\nusing FSH.Modules.Catalog.Contracts.v1.Brands;\nusing FSH.Modules.Catalog.Data;\nusing Mediator;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace FSH.Modules.Catalog.Features.v1.Brands.UpdateBrand;\n\npublic sealed class UpdateBrandCommandHandler(CatalogDbContext dbContext)\n    : ICommandHandler<UpdateBrandCommand, Guid>\n{\n    public async ValueTask<Guid> Handle(UpdateBrandCommand command, CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(command);\n\n        var brand = await dbContext.Brands\n            .FirstOrDefaultAsync(b => b.Id == command.BrandId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException($\"Brand {command.BrandId} not found.\");\n\n        brand.Update(command.Name, command.Description, command.LogoUrl);\n\n        bool slugTaken = await dbContext.Brands\n            .AnyAsync(b => b.Slug == brand.Slug && b.Id != brand.Id, cancellationToken)\n            .ConfigureAwait(false);\n        if (slugTaken)\n        {\n            throw new CustomException(\n                $\"Another brand with name '{command.Name}' already exists.\",\n                (IEnumerable<string>?)null,\n                HttpStatusCode.Conflict);\n        }\n\n        await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);\n        return brand.Id;\n    }\n}","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Catalog/Modules.Catalog/Features/v1/Brands/UpdateBrand/UpdateBrandCommandHandler.cs#L2-L38","documentation":"UpdateBrandCommandHandler loads the brand by command.BrandId and throws NotFoundException when no row matches; the API maps it to HTTP 404 and the update is aborted. Soft-deleted and cross-tenant rows are hidden by query filters, so they also appear as not found.","triggerScenarios":"Send/UpdateBrand command with a BrandId that does not exist, was deleted, or belongs to a different tenant.","commonSituations":"Editing from a stale list page after another user deleted the brand; wrong tenant context; ID copy/paste mistake.","solutions":["Re-fetch the brand list to confirm the BrandId still exists","Re-create the brand if it was (soft-)deleted","Ensure the request carries the correct tenant header"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"var brand = await mediator.Send(new GetBrandByIdQuery(id)); // throws 404 early if gone","typeGuard":null,"tryCatchPattern":"try { await mediator.Send(new UpdateBrandCommand(id, name, desc, logo)); }\ncatch (NotFoundException) { /* reload list; entity vanished */ }","preventionTips":["Use optimistic concurrency / re-fetch before edit forms","Keep stale IDs out of cached edit pages","Confirm tenant context before updates"],"tags":["not-found","http-404","update","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"}