fullstackhero/dotnet-starter-kit · warning · NotFoundException

Category not found.

Error message

Category {command.CategoryId} not found.

What it means

UpdateCategory throws NotFoundException when no category with command.CategoryId exists (default soft-delete filter applies, so soft-deleted categories also hit this). The update cannot proceed without an existing aggregate to mutate.

Solutions

  1. Reload the category list and retry the update with a current id.
  2. Verify the id exists and is not soft-deleted in the target database.
  3. Handle the NotFoundException in the client by showing 'category was deleted'.
  4. Check tenant headers/context are correct.

Example fix

// before: blind update
await api.updateCategory({ id: staleId, name: 'New Name' });

// after: refetch first
const cat = await api.getCategory(id); // throws NotFound -> prompt user
Defensive patterns

Strategy: try-catch

Validate before calling

const cat = await api.getCategory(id).catch(() => null);
if (!cat) return prompt('Category was deleted; reload before editing');

Try / catch

try { await api.updateCategory(payload); }
catch (e) { if (e.status === 404) { reloadList(); show('Category no longer exists'); } else throw e; }

Prevention

When it happens

Trigger: PUT/PATCH update for a CategoryId that: (1) was deleted before the update arrived, (2) is a wrong/typo Guid, (3) lives in another tenant.

Common situations: Two users editing concurrently — one deletes while the other saves; stale list page submitting updates for removed categories; automated scripts with hardcoded ids.

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/b1fbafe22d1a1a6e. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/UpdateCategory/UpdateCategoryCommandHandler.cs:20

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

namespace FSH.Modules.Catalog.Features.v1.Categories.UpdateCategory;

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

        var category = await dbContext.Categories
            .FirstOrDefaultAsync(c => c.Id == command.CategoryId, cancellationToken)
            .ConfigureAwait(false)
            ?? throw new NotFoundException($"Category {command.CategoryId} not found.");

        if (command.ParentCategoryId is { } parentId)
        {
            if (parentId == category.Id)
            {
                throw new CustomException(
                    "A category cannot be its own parent.",
                    (IEnumerable<string>?)null,
                    HttpStatusCode.BadRequest);
            }

            // Walk parent chain to detect cycles (parent → ancestor of self)
            var visited = new HashSet<Guid> { category.Id };
            Guid? cursor = parentId;
            while (cursor is { } cur)
            {
                if (!visited.Add(cur))
                {

View on GitHub (pinned to 3f2959e683)