{"record":{"id":"49713885c646cce7","repo":"fullstackhero/dotnet-starter-kit","slug":"a-category-with-name-command-name-already-exists","errorCode":null,"errorMessage":"A category with name '{command.Name}' already exists.","messagePattern":"A category with name '(.+?)' already exists\\.","errorType":"http","errorClass":"CustomException","httpStatus":409,"severity":"error","filePath":"src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/CreateCategory/CreateCategoryCommandHandler.cs","lineNumber":36,"sourceCode":"        if (command.ParentCategoryId is { } parentId)\n        {\n            bool parentExists = await dbContext.Categories\n                .AnyAsync(c => c.Id == parentId, cancellationToken)\n                .ConfigureAwait(false);\n            if (!parentExists)\n            {\n                throw new NotFoundException($\"Parent category {parentId} not found.\");\n            }\n        }\n\n        var category = Category.Create(command.Name, command.Description, command.ParentCategoryId);\n\n        bool slugTaken = await dbContext.Categories\n            .AnyAsync(c => c.Slug == category.Slug, cancellationToken)\n            .ConfigureAwait(false);\n        if (slugTaken)\n        {\n            throw new CustomException(\n                $\"A category with name '{command.Name}' already exists.\",\n                (IEnumerable<string>?)null,\n                HttpStatusCode.Conflict);\n        }\n\n        dbContext.Categories.Add(category);\n        await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);\n        return category.Id;\n    }\n}\n","sourceCodeStart":18,"sourceCodeEnd":47,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/CreateCategory/CreateCategoryCommandHandler.cs#L18-L47","documentation":"CreateCategoryCommandHandler computes the category slug from the name and throws CustomException with HTTP 409 Conflict when an existing category already has that Slug; nothing is persisted. Slug collisions arise from identical or near-identical names.","triggerScenarios":"Send/CreateCategory command whose Name slugifies to the Slug of an existing category in the tenant.","commonSituations":"Re-running an import/seed that creates categories; names differing only by case/punctuation; creating the same category in parallel requests.","solutions":["Use a different category name (or explicit unique slug)","Check the existing category — reuse or update it instead of creating","If the duplicate is soft-deleted, restore or purge it first"],"exampleFix":"// before\nawait mediator.Send(new CreateCategoryCommand(\"Shoes\", null, null)); // second time\n// after\nawait mediator.Send(new CreateCategoryCommand(\"Shoes Outlet\", null, null));","handlingStrategy":"validation","validationCode":"var existing = await mediator.Send(new SearchCategoriesQuery(name));\nif (existing.Items.Any(c => c.Slug == Slugify(name))) throw new InvalidOperationException(\"Category name already exists.\");","typeGuard":"bool IsNonEmptyName(string? n) => !string.IsNullOrWhiteSpace(n);","tryCatchPattern":"try { await mediator.Send(new CreateCategoryCommand(name, desc, parentId)); }\ncatch (CustomException ex) when (ex.StatusCode == HttpStatusCode.Conflict) { /* prompt for a different name */ }","preventionTips":["Deduplicate names before bulk imports","Use upsert semantics for idempotent seeding","Add a DB unique index on (TenantId, Slug) as a last line of defense"],"tags":["conflict","http-409","uniqueness","category"],"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"}