{"record":{"id":"4c7da8ca76e5b3e6","repo":"fullstackhero/dotnet-starter-kit","slug":"another-product-with-name-command-name-already-exists","errorCode":null,"errorMessage":"Another product with name '{command.Name}' already exists.","messagePattern":"Another product with name '(.+?)' already exists\\.","errorType":"exception","errorClass":"CustomException","httpStatus":409,"severity":"error","filePath":"src/Modules/Catalog/Modules.Catalog/Features/v1/Products/UpdateProduct/UpdateProductCommandHandler.cs","lineNumber":56,"sourceCode":"            if (!categoryExists)\n            {\n                throw new NotFoundException($\"Category {command.CategoryId} not found.\");\n            }\n        }\n\n        product.Update(\n            command.Name,\n            command.Description,\n            command.BrandId,\n            command.CategoryId,\n            command.IsActive);\n\n        bool slugTaken = await dbContext.Products\n            .AnyAsync(p => p.Slug == product.Slug && p.Id != product.Id, cancellationToken)\n            .ConfigureAwait(false);\n        if (slugTaken)\n        {\n            throw new CustomException(\n                $\"Another product with name '{command.Name}' already exists.\",\n                (IEnumerable<string>?)null,\n                HttpStatusCode.Conflict);\n        }\n\n        await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);\n        return product.Id;\n    }\n}\n","sourceCodeStart":38,"sourceCodeEnd":66,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Catalog/Modules.Catalog/Features/v1/Products/UpdateProduct/UpdateProductCommandHandler.cs#L38-L66","documentation":"After updating, the handler slugifies the product name and checks whether another product already uses that slug; if so it throws CustomException with HTTP 409 Conflict — product names (via slugs) must be unique per module rules.","triggerScenarios":"UpdateProductCommand renaming a product to a name whose generated slug matches another product's slug (p.Slug == product.Slug && p.Id != product.Id). Also fires when only casing/punctuation changes, since slugify normalizes them to the same slug.","commonSituations":"Two editors rename different products to the same title; renaming 'Pro X' when 'Pro  X' already exists (identical slugs); bulk import scripts not checking name collisions.","solutions":["Pick a different product name (add a variant/suffix) and retry.","Check the existing product list for the colliding name before saving.","If the two products should be one, delete/merge the duplicate instead of renaming.","Catch CustomException with the 409 status in the client and show a friendly 'name taken' message."],"exampleFix":"// before\nawait mediator.Send(new UpdateProductCommand { ProductId = id, Name = newName });\n// after\nvar slug = newName.ToSlug();\nbool taken = await db.Products.AnyAsync(p => p.Slug == slug && p.Id != id, ct);\nif (taken) newName = $\"{newName} 2\"; // or prompt user\nawait mediator.Send(new UpdateProductCommand { ProductId = id, Name = newName }, ct);","handlingStrategy":"try-catch","validationCode":"var slug = newName.ToSlug();\nbool taken = await dbContext.Products.AnyAsync(p => p.Slug == slug && p.Id != productId, ct);\nif (taken) throw new ValidationException(\"Another product already uses this name.\");","typeGuard":null,"tryCatchPattern":"try { await mediator.Send(cmd, ct); }\ncatch (CustomException ex) when (ex.StatusCode == HttpStatusCode.Conflict)\n{ ModelState.AddModelError(nameof(cmd.Name), \"Product name already in use\"); return Results.Conflict(); }","preventionTips":["Pre-check slug availability (debounced API check) in the rename form.","Remember slugify collapses casing/punctuation — 'Pro X' and 'Pro X!' collide.","In bulk imports, generate unique slugs (append counter) instead of failing.","Show 409 as a user-facing 'name taken' message, not a generic error."],"tags":["catalog","conflict","duplicate","slug","http-409"],"backgroundTag":"resource-already-exists","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"}