fullstackhero/dotnet-starter-kit · error · UnauthorizedException
no current user
Error message
no current user
What it means
ListChannelMessages throws UnauthorizedException('no current user') when currentUser.GetUserId() returns Guid.Empty, i.e. no authenticated identity on the request. Maps to HTTP 401 and is thrown before the channel lookup to avoid leaking channel existence to anonymous callers.
Solutions
- Obtain/refresh a valid access token and send it in the Authorization header
- Fix token refresh logic so expired tokens are renewed before calls
- Ensure test harnesses/background jobs seed an ICurrentUser instead of calling handlers raw
- Validate JWT bearer options (issuer/audience) so tokens authenticate
Defensive patterns
Strategy: try-catch
Validate before calling
if (!auth.isAuthenticated()) throw new Error('login required before listing messages'); Type guard
function isAuthed(ctx: { UserId?: string }): boolean { return typeof ctx.UserId === 'string' && ctx.UserId !== '00000000-0000-0000-0000-000000000000'; } Try / catch
try { return await listChannelMessages(channelId); }
catch (e) { if (isUnauthorized(e)) { await auth.refresh(); return listChannelMessages(channelId); } throw e; } Prevention
- Central token refresh before calls
- Attach bearer token globally via interceptor
- Seed a current user in integration tests
- Treat 401 as re-auth signal, not a bug
When it happens
Trigger: Listing channel messages without a valid JWT; missing, expired, or otherwise unauthenticated request context.
Common situations: SignalR/SSE or background contexts calling the handler without user propagation, expired tokens, or misconfigured auth middleware in tests.
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/928641cbc51c0d55.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Messages/ListChannelMessages/ListChannelMessagesQueryHandler.cs:25
using FSH.Modules.Chat.Features.v1.Internal;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Chat.Features.v1.Messages.ListChannelMessages;
public sealed class ListChannelMessagesQueryHandler(
ChatDbContext db,
ICurrentUser currentUser,
IMediator mediator)
: IQueryHandler<ListChannelMessagesQuery, ReadOnlyCollection<MessageDto>>
{
public async ValueTask<ReadOnlyCollection<MessageDto>> Handle(
ListChannelMessagesQuery query,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(query);
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 == query.ChannelId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException("Channel not found.");
channel.RequireMember(currentUserId);
// Top-level only (no thread replies). Guid v7 monotonic → Id desc = time desc.
IQueryable<Domain.Message> q = db.Messages
.Where(m => m.ChannelId == query.ChannelId && m.ParentMessageId == null);
if (query.Before is { } beforeId)
{
q = q.Where(m => m.Id.CompareTo(beforeId) < 0);
}
var rows = await q
.OrderByDescending(m => m.Id)View on GitHub (pinned to 3f2959e683)