fullstackhero/dotnet-starter-kit · error · UnauthorizedException

no current user

Error message

no current user

What it means

PinMessageCommandHandler throws UnauthorizedException('no current user') when currentUser.GetUserId() returns Guid.Empty, meaning the request carried no authenticated identity. This is the library's 401 path, thrown before any message lookup.

Solutions

  1. Refresh/acquire a valid access token and send it with the request
  2. Verify JWT bearer options and that authentication runs before authorization
  3. Seed an ICurrentUser in test harnesses calling handlers directly
  4. Confirm the client attaches the Authorization header on mutation calls
Defensive patterns

Strategy: try-catch

Validate before calling

if (!auth.isAuthenticated()) await auth.login();

Type guard

function canPin(user: { Id: string } | null): boolean { return user !== null && user.Id !== '00000000-0000-0000-0000-000000000000'; }

Try / catch

try { await pinMessage(messageId); }
catch (e) { if (isUnauthorized(e)) { await auth.refresh(); return pinMessage(messageId); } throw e; }

Prevention

When it happens

Trigger: Pinning a message without a valid JWT; missing/expired/invalid bearer token.

Common situations: Expired token not refreshed in the client, raw handler invocation in tests without a current user, or auth middleware misconfiguration.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/7bae0bfc9b8d8973. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Messages/PinMessage/PinMessageCommandHandler.cs:23

using FSH.Modules.Chat.Data;
using FSH.Modules.Chat.Features.v1.Internal;
using Mediator;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;

namespace FSH.Modules.Chat.Features.v1.Messages.PinMessage;

public sealed class PinMessageCommandHandler(
    ChatDbContext db,
    ICurrentUser currentUser,
    IHubContext<AppHub> hub)
    : ICommandHandler<PinMessageCommand, Unit>
{
    public async ValueTask<Unit> Handle(PinMessageCommand 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 message = await db.Messages.FirstOrDefaultAsync(m => m.Id == cmd.MessageId, cancellationToken)
            .ConfigureAwait(false)
            ?? throw new NotFoundException("Message not found.");

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

        message.Pin(currentUserId);
        await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

        await hub.Clients.Group($"channel:{channel.Id}")
            .SendAsync("ChatMessagePinned", message.ToDto(), cancellationToken)
            .ConfigureAwait(false);
        return Unit.Value;

View on GitHub (pinned to 3f2959e683)