{"record":{"id":"4d309e9d50f901fb","repo":"fullstackhero/dotnet-starter-kit","slug":"no-current-user-getchannelbyidqueryhandler","errorCode":null,"errorMessage":"no current user","messagePattern":"no current user","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"src/Modules/Chat/Modules.Chat/Features/v1/Channels/GetChannelById/GetChannelByIdQueryHandler.cs","lineNumber":21,"sourceCode":"using FSH.Modules.Chat.Contracts.v1.DTOs;\nusing FSH.Modules.Chat.Contracts.v1.Queries;\nusing FSH.Modules.Chat.Data;\nusing FSH.Modules.Chat.Features.v1.Internal;\nusing Mediator;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace FSH.Modules.Chat.Features.v1.Channels.GetChannelById;\n\npublic sealed class GetChannelByIdQueryHandler(\n    ChatDbContext db,\n    ICurrentUser currentUser)\n    : IQueryHandler<GetChannelByIdQuery, ChannelDto>\n{\n    public async ValueTask<ChannelDto> Handle(GetChannelByIdQuery q, CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(q);\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.AsNoTracking()\n            .FirstOrDefaultAsync(c => c.Id == q.ChannelId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException(\"Channel not found.\");\n\n        // Private channels & DMs: must be a member. Public channels: anyone with View can see them.\n        if (channel.IsPrivate)\n        {\n            channel.RequireMember(currentUserId);\n        }\n\n        var member = channel.Members.FirstOrDefault(m => string.Equals(m.UserId, currentUserId, StringComparison.Ordinal));\n        int unread = 0;\n        if (member is not null)\n        {\n            unread = await db.Messages.AsNoTracking()","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Chat/Modules.Chat/Features/v1/Channels/GetChannelById/GetChannelByIdQueryHandler.cs#L3-L39","documentation":"GetChannelByIdQueryHandler requires an authenticated caller; currentUser.GetUserId() returning Guid.Empty means no user was resolved from the JWT/context. The handler throws UnauthorizedException before doing any data access, so the request never reaches the channel lookup.","triggerScenarios":"Calling GET /channels/{channelId} with a missing, malformed, or expired JWT Bearer token, or from an anonymous context where ICurrentUser.GetUserId() yields Guid.Empty.","commonSituations":"Token expired client-side but request still fired; Authorization header stripped by a proxy/gateway; hitting the endpoint without the [Authorize]-effective auth scheme during local testing; clock skew invalidating the JWT.","solutions":["Refresh or re-acquire the JWT and retry with a valid Authorization: Bearer header.","Verify the auth middleware/JWT config (issuer, audience, signing key) on the host.","Ensure the gateway/proxy forwards the Authorization header.","Confirm the user claim mapping (nameidentifier) is populated in the token."],"exampleFix":"// before\nfetch(`${base}/channels/${id}`);\n// after\nconst res = await fetch(`${base}/channels/${id}`, {\n  headers: { Authorization: `Bearer ${await getValidAccessToken()}` }\n});\nif (res.status === 401) await reauthenticate();","handlingStrategy":"try-catch","validationCode":"if (!accessToken || isTokenExpired(accessToken)) throw new Error('Not authenticated');","typeGuard":"const isAuthenticated = (u: unknown): u is { id: string } =>\n  !!u && typeof (u as any).id === 'string' && (u as any).id.length > 0;","tryCatchPattern":"try { ... } catch (e) {\n  if (isUnauthorized(e)) { await reauthenticate(); retry(); }\n  else throw e;\n}","preventionTips":["Attach a valid Bearer token to every channel request.","Refresh tokens before expiry (proactively, not on failure only).","Use an axios/fetch interceptor that handles 401 once, centrally.","Verify the Authorization header isn't stripped by proxies in staging."],"tags":["auth","jwt","unauthorized"],"backgroundTag":"authentication-required","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"}