fullstackhero/dotnet-starter-kit · error · NotFoundException

Brand not found.

Error message

Brand {command.BrandId} not found.

What it means

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.

Solutions

  1. Re-fetch the brand list to confirm the BrandId still exists
  2. Re-create the brand if it was (soft-)deleted
  3. Ensure the request carries the correct tenant header
Defensive patterns

Strategy: try-catch

Validate before calling

var brand = await mediator.Send(new GetBrandByIdQuery(id)); // throws 404 early if gone

Try / catch

try { await mediator.Send(new UpdateBrandCommand(id, name, desc, logo)); }
catch (NotFoundException) { /* reload list; entity vanished */ }

Prevention

When it happens

Trigger: Send/UpdateBrand command with a BrandId that does not exist, was deleted, or belongs to a different tenant.

Common situations: Editing from a stale list page after another user deleted the brand; wrong tenant context; ID copy/paste mistake.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Brands/UpdateBrand/UpdateBrandCommandHandler.cs:20

using FSH.Framework.Core.Exceptions;
using FSH.Modules.Catalog.Contracts.v1.Brands;
using FSH.Modules.Catalog.Data;
using Mediator;
using Microsoft.EntityFrameworkCore;

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

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

        var brand = await dbContext.Brands
            .FirstOrDefaultAsync(b => b.Id == command.BrandId, cancellationToken)
            .ConfigureAwait(false)
            ?? throw new NotFoundException($"Brand {command.BrandId} not found.");

        brand.Update(command.Name, command.Description, command.LogoUrl);

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

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

View on GitHub (pinned to 3f2959e683)