fullstackhero/dotnet-starter-kit · error · NotFoundException

Channel not found.

Error message

Channel not found.

What it means

AddChannelMembersCommandHandler throws NotFoundException when no channel with cmd.ChannelId exists in db.Channels. The lookup uses FirstOrDefaultAsync and throws instead of returning null so the endpoint maps to 404.

Solutions

  1. Verify the ChannelId exists (and isn't archived) before inviting members
  2. Re-fetch the channel list instead of using a cached ID
  3. Log the incoming ChannelId and confirm it against the database

Example fix

// before
await addMembers(channelIdFromCache, userIds);
// after
var channel = await getChannel(channelId);
if (channel) await addMembers(channelId, userIds);
Defensive patterns

Strategy: validation

Validate before calling

var exists = await db.Channels.AnyAsync(c => c.Id == cmd.ChannelId);
if (!exists) return 404; // before inviting

Type guard

bool channelExists = channel is not null;

Try / catch

try { await addMembers(channelId, userIds); }
catch (NotFoundException) { /* refresh channel list; remove stale entry */ }

Prevention

When it happens

Trigger: Posting AddChannelMembers with a ChannelId that was never created, was archived/deleted (soft-delete removes it from queries), or a GUID typo / channel from another environment.

Common situations: Client cached a channel ID after it was archived; copy-pasted ID from another tenant/database; frontend using an undefined/stale variable as the ID.

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

Appendix: source

Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Channels/AddChannelMembers/AddChannelMembersCommandHandler.cs:29

namespace FSH.Modules.Chat.Features.v1.Channels.AddChannelMembers;

public sealed class AddChannelMembersCommandHandler(
    ChatDbContext db,
    ICurrentUser currentUser,
    IHubContext<AppHub> hub)
    : ICommandHandler<AddChannelMembersCommand, Unit>
{
    public async ValueTask<Unit> Handle(AddChannelMembersCommand cmd, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(cmd);
        var userId = currentUser.GetUserId();
        if (userId == Guid.Empty) throw new UnauthorizedException("no current user");
        var currentUserId = userId.ToString();

        var channel = await db.Channels.FirstOrDefaultAsync(c => c.Id == cmd.ChannelId, cancellationToken)
            .ConfigureAwait(false)
            ?? throw new NotFoundException("Channel not found.");

        // Members can invite to public channels they belong to; private channels require Admin.
        var caller = channel.RequireMember(currentUserId);
        if (channel.IsPrivate && caller.Role != ChannelMemberRole.Admin)
        {
            throw new ForbiddenException("Only channel admins can add members to private channels.");
        }

        var newlyAdded = new List<string>();
        foreach (var uid in cmd.UserIds.Distinct(StringComparer.Ordinal))
        {
            // Skip duplicates silently — endpoint is idempotent for already-members.
            if (channel.Members.Any(m => string.Equals(m.UserId, uid, StringComparison.Ordinal))) continue;
            channel.AddMember(uid, currentUserId);
            newlyAdded.Add(uid);
        }

        await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

View on GitHub (pinned to 3f2959e683)