fullstackhero/dotnet-starter-kit · error · NotFoundException
Channel not found.
Error message
Channel not found.
What it means
RestoreChannelCommandHandler looks the channel up with IgnoreQueryFilters() specifically so an archived (soft-deleted) channel can be found, then throws NotFoundException only if no channel with that Id exists at all (including deleted). If the channel exists but isn't deleted, the handler returns idempotently without error.
Solutions
- Verify the id exists in the Channels table (including IsDeleted rows) in the current tenant's DB.
- Note restore is idempotent — a 404 means the row is truly gone, not already restored.
- Use the audit/soft-delete data to confirm the channel was soft- (not hard-) deleted.
- Handle the 404 in the archive UI by removing the entry from the list.
Example fix
// before
await api.post(`/channels/${id}/restore`); // assumes it's just archived
// after
try {
await api.post(`/channels/${id}/restore`);
} catch (e) {
if (isNotFound(e)) removeFromArchiveList(id); // channel no longer exists at all
else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
const archived = await fetchArchivedChannel(channelId); // must still exist (soft-deleted ok)
if (!archived) throw new Error('Channel no longer exists'); Try / catch
try { ... } catch (e) {
if (isNotFound(e)) { removeFromArchiveUi(channelId); notify('Channel no longer exists'); }
else throw e;
} Prevention
- Distinguish soft-deleted (restorable) from hard-deleted (gone) channels in the archive UI.
- Refresh the archive list on cleanup-job completion.
- Never assume restore is the fix for a missing channel — 404 means the row is truly absent.
- Verify tenant context before restoring ids from logs/backups.
When it happens
Trigger: Restoring a channel id that never existed, was hard-deleted, or belongs to another tenant — even IgnoreQueryFilters can't find it; calling restore on an id mistyped or from a different environment's DB.
Common situations: Archive list out of sync with the DB (channel purged); cross-tenant restore attempt; id taken from an audit log of another environment; duplicate restore after a hard delete by cleanup jobs.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/1cf75d124dfd28c4.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Channels/RestoreChannel/RestoreChannelCommandHandler.cs:20
using FSH.Modules.Chat.Contracts.v1.Commands;
using FSH.Modules.Chat.Data;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Chat.Features.v1.Channels.RestoreChannel;
public sealed class RestoreChannelCommandHandler(ChatDbContext db)
: ICommandHandler<RestoreChannelCommand, Unit>
{
public async ValueTask<Unit> Handle(RestoreChannelCommand cmd, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(cmd);
// IgnoreQueryFilters bypasses the SoftDelete filter so we can find an archived channel.
var channel = await db.Channels.IgnoreQueryFilters()
.FirstOrDefaultAsync(c => c.Id == cmd.ChannelId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException("Channel not found.");
if (!channel.IsDeleted) return Unit.Value; // idempotent
channel.Restore();
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
return Unit.Value;
}
}
View on GitHub (pinned to 3f2959e683)