fullstackhero/dotnet-starter-kit · error · UnauthorizedException

no current user

Error message

no current user

What it means

AddChannelMembersCommandHandler rejects the command with UnauthorizedException when currentUser.GetUserId() returns Guid.Empty, meaning no authenticated user is associated with the request context. The handler needs a current user to attribute the membership change and run permission checks.

Solutions

  1. Ensure the request carries a valid, non-expired JWT bearer token
  2. Check authentication/401 handling at the client and re-login on token expiry
  3. In tests, mock ICurrentUser.GetUserId() to return a real Guid or use the authenticated test client

Example fix

// before (test)
var handler = new AddChannelMembersCommandHandler(db, currentUserSubstitute); // GetUserId -> Guid.Empty
// after
currentUserSubstitute.GetUserId().Returns(Guid.NewGuid());
Defensive patterns

Strategy: validation

Validate before calling

var userId = currentUser.GetUserId();
if (userId == Guid.Empty) throw new UnauthorizedException("no current user");

Type guard

bool isAuthenticated = currentUser.GetUserId() != Guid.Empty;

Try / catch

try { await handler.Handle(cmd, ct); }
catch (UnauthorizedException) { /* return 401 / trigger re-login */ }

Prevention

When it happens

Trigger: Invoking the AddChannelMembers endpoint without a valid JWT, with an expired/anonymous identity, or in tests without a mocked ICurrentUser returning a real Guid.

Common situations: Missing/invalid Authorization header; token expired; integration tests forgetting to authenticate the request; calling the handler directly with an unconfigured ICurrentUser substitute.

Related errors


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

Appendix: source

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

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.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;

View on GitHub (pinned to 3f2959e683)