fullstackhero/dotnet-starter-kit · warning · NotFoundException

Category not found.

Error message

Category {command.CategoryId} not found.

What it means

RestoreCategory looks the category up with IgnoreQueryFilters([QueryFilters.SoftDelete]) so soft-deleted rows are visible, but still throws NotFoundException when no row with the given CategoryId exists at all — including rows hard-deleted or never created. This means 'not even in the recycle bin'.

Solutions

  1. Check the row exists physically: SELECT * FROM "Categories" WHERE "Id" = '<id>' — if absent, it cannot be restored.
  2. Re-fetch the category list from the API instead of using a stale client-side id.
  3. Verify tenant context matches the row's tenant.
  4. If the row was purged, recreate the category rather than restoring.
Defensive patterns

Strategy: validation

Validate before calling

// ensure the category actually exists (even deleted) before restoring
const row = await api.listCategories({ ids: [id], includeDeleted: true });
if (!row.items.length) return alert('Category no longer exists and cannot be restored');

Type guard

const isGuid = (v) => typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v);

Try / catch

try { await api.restoreCategory(id); }
catch (e) { if (e.status === 404) show('Not found — it may have been permanently deleted'); else throw e; }

Prevention

When it happens

Trigger: POST restore for a CategoryId that: (1) was hard-deleted (physically removed), (2) never existed (typo/fabricated Guid), (3) exists only in another tenant.

Common situations: Retrying a restore after the row was permanently purged by a cleanup job; client caching a stale id of a hard-deleted category; ids copied between environments.

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

Appendix: source

Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/RestoreCategory/RestoreCategoryCommandHandler.cs:21

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

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

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

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

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

View on GitHub (pinned to 3f2959e683)