{"record":{"id":"c06c0780f94ae0ac","repo":"fullstackhero/dotnet-starter-kit","slug":"channel-not-found-getpinnedmessagesqueryhandler","errorCode":null,"errorMessage":"Channel not found.","messagePattern":"Channel not found\\.","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Chat/Modules.Chat/Features/v1/Messages/GetPinnedMessages/GetPinnedMessagesQueryHandler.cs","lineNumber":30,"sourceCode":"\npublic sealed class GetPinnedMessagesQueryHandler(\n    ChatDbContext db,\n    ICurrentUser currentUser,\n    IMediator mediator)\n    : IQueryHandler<GetPinnedMessagesQuery, ReadOnlyCollection<MessageDto>>\n{\n    public async ValueTask<ReadOnlyCollection<MessageDto>> Handle(\n        GetPinnedMessagesQuery query,\n        CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(query);\n        var userId = currentUser.GetUserId();\n        if (userId == Guid.Empty) throw new UnauthorizedException(\"no current user\");\n        var currentUserId = userId.ToString();\n\n        var channel = await db.Channels.FirstOrDefaultAsync(c => c.Id == query.ChannelId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException(\"Channel not found.\");\n        channel.RequireMember(currentUserId);\n\n        var rows = await db.Messages\n            .Where(m => m.ChannelId == query.ChannelId && m.IsPinned)\n            .OrderByDescending(m => m.PinnedAtUtc)\n            .Include(m => m.Attachments)\n            .Include(m => m.Mentions)\n            .AsNoTracking()\n            .ToListAsync(cancellationToken)\n            .ConfigureAwait(false);\n\n        var dtos = rows.Select(m => m.ToDto()).ToList();\n        var resolved = await ChatAttachmentUrls.ResolveAsync(dtos, mediator, cancellationToken).ConfigureAwait(false);\n        return resolved.AsReadOnly();\n    }\n}\n","sourceCodeStart":12,"sourceCodeEnd":47,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Chat/Modules.Chat/Features/v1/Messages/GetPinnedMessages/GetPinnedMessagesQueryHandler.cs#L12-L47","documentation":"The handler queries db.Channels for query.ChannelId and throws NotFoundException (HTTP 404) when no matching row exists. This library throws it so callers get a clean 404 instead of a null-reference later at channel.RequireMember.","triggerScenarios":"GET pinned messages with a ChannelId that does not exist in the Channels table (or exists only in another tenant, hidden by the global tenant query filter).","commonSituations":"Stale/deleted channel id cached in the client, id from a different tenant, wrong id passed in a route, or tests using seeded ids that were never created.","solutions":["Verify the ChannelId exists (and in the current tenant) before calling the endpoint","Refresh the channel list on the client; clear stale cached channel ids","Check the X-Tenant / tenant resolution matches the tenant the channel was created in","If the channel should exist, inspect the Channels table for soft-deletes or migration gaps"],"exampleFix":"// before\nawait apiFetch('/api/v1/channels/'+channelId+'/messages/pinned');\n// after\nconst channel = channels.find(c => c.id === channelId);\nif (!channel) throw new Error('channel '+channelId+' not loaded');\nawait apiFetch('/api/v1/channels/'+channelId+'/messages/pinned');","handlingStrategy":"validation","validationCode":"const channel = channels.find(c => c.id === channelId);\nif (!channel) throw new Error(`channel ${channelId} not loaded`);","typeGuard":"function channelExists(channels: Channel[], id: string): channels is Channel[] & { length: number } { return channels.some(c => c.id === id); }","tryCatchPattern":"try { return await getPinnedMessages(channelId); }\ncatch (e) { if (isNotFound(e)) { invalidateChannelCache(channelId); notifyUser('Channel no longer available'); return []; } throw e; }","preventionTips":["Refresh channel lists after mutations/deletes","Never persist channel ids across sessions without revalidation","Verify tenant header matches the channel's tenant","Handle 404 by cleaning stale UI references"],"tags":["chat","not-found","channel"],"backgroundTag":"entity-not-found","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}