fullstackhero/dotnet-starter-kit · error · CustomException

A brand with name ' ' already exists.

Error message

A brand with name '{command.Name}' already exists.

What it means

CreateBrandCommandHandler throws a CustomException with HTTP 409 Conflict when a brand whose computed Slug collides with the new brand's Slug already exists in the Catalog database. The check runs before the new brand is added, so nothing is persisted. The message mentions the brand Name because the slug is derived from it.

Solutions

  1. Pick a different brand name (or explicitly supply a distinct slug) and retry
  2. Query GET /brands/v1 to confirm the existing brand — if it is the same brand you want, update it instead of creating a new one
  3. If the conflicting row is a soft-deleted brand, restore or permanently remove it via the Restore/Delete endpoints

Example fix

// before
await mediator.Send(new CreateBrandCommand("Acme")); // again
// after
await mediator.Send(new UpdateBrandCommand(existingId, "Acme", description, logoUrl));
Defensive patterns

Strategy: validation

Validate before calling

var slugTaken = await apiClient.GET<bool>($"/brands/v1/exists?slug={Uri.EscapeDataString(slug)}");
if (slugTaken) throw new InvalidOperationException($"Brand name '{name}' is already in use.");

Type guard

bool IsUsableName(string? name) => !string.IsNullOrWhiteSpace(name) && name.Trim().Length >= 2;

Try / catch

try { await mediator.Send(new CreateBrandCommand(name)); }
catch (CustomException ex) when (ex.StatusCode == HttpStatusCode.Conflict) { /* surface 'name already exists' to the user */ }

Prevention

When it happens

Trigger: POST/CreateBrand command whose Name (after slug normalization) matches the Slug of an existing brand row in dbContext.Brands.

Common situations: Re-creating a brand that was created before; creating two brands whose names differ only by case, punctuation or whitespace and therefore slugify identically; running seed/import scripts twice.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/71d3b343b72b17d1. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Brands/CreateBrand/CreateBrandCommandHandler.cs:25

using Microsoft.EntityFrameworkCore;

namespace FSH.Modules.Catalog.Features.v1.Brands.CreateBrand;

public sealed class CreateBrandCommandHandler(CatalogDbContext dbContext)
    : ICommandHandler<CreateBrandCommand, Guid>
{
    public async ValueTask<Guid> Handle(CreateBrandCommand command, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(command);

        var brand = Brand.Create(command.Name, command.Description, command.LogoUrl);

        bool slugTaken = await dbContext.Brands
            .AnyAsync(b => b.Slug == brand.Slug, cancellationToken)
            .ConfigureAwait(false);
        if (slugTaken)
        {
            throw new CustomException(
                $"A brand with name '{command.Name}' already exists.",
                (IEnumerable<string>?)null,
                HttpStatusCode.Conflict);
        }

        dbContext.Brands.Add(brand);
        await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
        return brand.Id;
    }
}

View on GitHub (pinned to 3f2959e683)