{"record":{"id":"644a793e85b2a4f4","repo":"fullstackhero/dotnet-starter-kit","slug":"another-brand-with-name-command-name-already-exists","errorCode":null,"errorMessage":"Another brand with name '{command.Name}' already exists.","messagePattern":"Another brand with name '(.+?)' already exists\\.","errorType":"http","errorClass":"CustomException","httpStatus":409,"severity":"error","filePath":"src/Modules/Catalog/Modules.Catalog/Features/v1/Brands/UpdateBrand/UpdateBrandCommandHandler.cs","lineNumber":29,"sourceCode":"    : 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}\n","sourceCodeStart":11,"sourceCodeEnd":39,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Catalog/Modules.Catalog/Features/v1/Brands/UpdateBrand/UpdateBrandCommandHandler.cs#L11-L39","documentation":"After applying brand.Update (which recomputes the slug), UpdateBrandCommandHandler checks for another brand (b.Id != brand.Id) with the same Slug and throws CustomException with HTTP 409 Conflict if one exists. The rename is not saved. This is the update-time counterpart of the create-time uniqueness check.","triggerScenarios":"Send/UpdateBrand command whose new Name slugifies to the Slug of a different existing brand.","commonSituations":"Renaming a brand to a name already used by another brand (case/punctuation differences slugify the same); two admins renaming concurrently; bulk rename scripts.","solutions":["Choose a name that does not collide with any other brand's slug","Look up existing brands first to pick a unique name","If both brands should be one, delete/merge instead of renaming"],"exampleFix":"// before\nawait mediator.Send(new UpdateBrandCommand(id, \"Acme\", ...)); // collides\n// after\nawait mediator.Send(new UpdateBrandCommand(id, \"Acme Europe\", ...)); // unique slug","handlingStrategy":"validation","validationCode":"var others = await mediator.Send(new SearchBrandsQuery(newName));\nif (others.Items.Any(b => b.Id != id && b.Slug == Slugify(newName))) throw new InvalidOperationException(\"Name conflicts with another brand.\");","typeGuard":null,"tryCatchPattern":"try { await mediator.Send(new UpdateBrandCommand(id, newName, desc, logo)); }\ncatch (CustomException ex) when (ex.StatusCode == HttpStatusCode.Conflict) { /* show 'name already used' */ }","preventionTips":["Uniqueness-check the new name before submitting","Avoid names differing only by case/punctuation from existing brands","Serialize concurrent renames through a single admin path or unique index"],"tags":["conflict","http-409","uniqueness","rename","catalog"],"backgroundTag":"duplicate-name-conflict","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"}