fullstackhero/dotnet-starter-kit · error · CustomException
A category cannot be its own parent.
Error message
A category cannot be its own parent.
What it means
UpdateCategory validates that a category's new ParentCategoryId is not the category's own id, throwing CustomException with 400 BadRequest. A self-parent would make the hierarchy ill-formed, so it is rejected up front before cycle walking.
Solutions
- Exclude the category itself from the parent-selection dropdown in the UI.
- Fix the payload so parentCategoryId differs from the category's id.
- Send parentCategoryId = null if the intent was to make it a root category.
- Add client-side validation rejecting parentId === id before submitting.
Example fix
// before: dropdown includes self
{categories.map(c => <option value={c.id}>{c.name}</option>)}
// after: exclude self
{categories.filter(c => c.id !== editingId).map(c => <option value={c.id}>{c.name}</option>)} Defensive patterns
Strategy: validation
Validate before calling
if (payload.parentCategoryId === categoryId) {
return formError('A category cannot be its own parent.');
} Try / catch
try { await api.updateCategory(payload); }
catch (e) { if (e.status === 400) formError(e.message); else throw e; } Prevention
- Exclude the current category from its own parent dropdown
- Treat empty parent selection as null (root), not as self-id
- Add a form-level zod/refine rule parentId !== id
When it happens
Trigger: PATCH update where the body's parentCategoryId equals the id in the route/body — e.g. a form that lets the category select itself, or a client echoing the id into the parent field when the user clears the parent selection.
Common situations: Frontend dropdown not excluding the current category from parent options; bulk import mapping parent column incorrectly; API consumers constructing payloads programmatically.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Setting this parent would create a cycle.
- Unknown visibility value
- cannot impersonate yourself
- File exceeds max size of
- File exceeds max size of
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/49bd8d2b6e16a37c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Catalog/Modules.Catalog/Features/v1/Categories/UpdateCategory/UpdateCategoryCommandHandler.cs:26
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))
{
throw new CustomException(
"Setting this parent would create a cycle.",
(IEnumerable<string>?)null,
HttpStatusCode.BadRequest);
}
cursor = await dbContext.CategoriesView on GitHub (pinned to 3f2959e683)