fullstackhero/dotnet-starter-kit · error · NotFoundException
Channel not found.
Error message
Channel not found.
What it means
ArchiveChannelCommandHandler throws NotFoundException when no channel with cmd.ChannelId exists. Channels are soft-deleted on archive, and archived channels no longer resolve via db.Channels, so archiving (or re-archiving) a missing/archived channel yields 404.
Solutions
- Confirm the channel exists and is not already archived before calling
- Refresh channel state from the server; treat 404 as 'already gone' and update UI
- Deduplicate/serialize archive requests (disable button while pending)
Example fix
// before
await archiveChannel(channelId); // may 404 if already archived
// after
if (!channel.isArchived) {
await archiveChannel(channelId);
} Defensive patterns
Strategy: validation
Validate before calling
var channel = await db.Channels.FirstOrDefaultAsync(c => c.Id == cmd.ChannelId); if (channel is null || channel.IsArchived) skip/404;
Type guard
bool archivable = channel is { } c && !c.IsArchived; Try / catch
try { await archiveChannel(channelId); }
catch (NotFoundException) { /* already archived/gone — sync UI */ } Prevention
- Refresh channel state before archiving
- Disable archive button while pending to avoid double-submit
- Treat 404 as idempotent success for archive flows
When it happens
Trigger: Archiving a ChannelId that doesn't exist; re-archiving an already-archived channel; stale client cache holding a deleted channel's ID.
Common situations: Double-click on the archive button; another admin archived first; environment mismatch (testing ID against production DB).
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/0ebed856e72b97bc.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Channels/ArchiveChannel/ArchiveChannelCommandHandler.cs:24
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Chat.Features.v1.Channels.ArchiveChannel;
public sealed class ArchiveChannelCommandHandler(
ChatDbContext db,
ICurrentUser currentUser)
: ICommandHandler<ArchiveChannelCommand, Unit>
{
public async ValueTask<Unit> Handle(ArchiveChannelCommand cmd, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(cmd);
var userId = currentUser.GetUserId();
if (userId == Guid.Empty) throw new UnauthorizedException("no current user");
var channel = await db.Channels.FirstOrDefaultAsync(c => c.Id == cmd.ChannelId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException("Channel not found.");
channel.RequireAdmin(userId.ToString());
// Explicit soft-delete (not db.Remove): removing the aggregate cascades Deleted onto
// the ChannelMember rows, which the audit interceptor does not rescue (they're FK
// children, not owned), so they'd be hard-deleted and lost on restore.
channel.Archive(userId.ToString());
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
return Unit.Value;
}
}
View on GitHub (pinned to 3f2959e683)