fullstackhero/dotnet-starter-kit · error · UnauthorizedException

no current user

Error message

no current user

What it means

FindOrCreateDmCommandHandler throws UnauthorizedException when currentUser.GetUserId() returns Guid.Empty, i.e. no authenticated caller. The DM channel is created between the current user and the given users, so identity is required before any other validation.

Solutions

  1. Authenticate the request with a valid bearer token
  2. Handle 401 by re-authenticating/refreshing before retrying
  3. In tests, mock ICurrentUser.GetUserId() to return a real Guid

Example fix

// before
currentUser.GetUserId().Returns(Guid.Empty); // handler throws
// after
currentUser.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 findOrCreateDm(userIds); }
catch (UnauthorizedException) { /* re-authenticate */ }
catch (CustomException) { /* 'Cannot DM yourself.' — filter out own id */ }

Prevention

When it happens

Trigger: Calling FindOrCreateDm without a valid JWT, with an expired token, or in tests without a configured ICurrentUser. Note: passing your own ID in UserIds instead raises 'Cannot DM yourself.' (CustomException), not this error.

Common situations: Session expired before opening a DM; missing Authorization header; integration tests without auth setup.

Related errors


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

Appendix: source

Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Channels/FindOrCreateDm/FindOrCreateDmCommandHandler.cs:24

using FSH.Modules.Chat.Data;
using FSH.Modules.Chat.Domain;
using Mediator;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;

namespace FSH.Modules.Chat.Features.v1.Channels.FindOrCreateDm;

public sealed class FindOrCreateDmCommandHandler(
    ChatDbContext db,
    IHubContext<AppHub> hub,
    ICurrentUser currentUser)
    : ICommandHandler<FindOrCreateDmCommand, Guid>
{
    public async ValueTask<Guid> Handle(FindOrCreateDmCommand 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 otherIds = cmd.UserIds.Distinct(StringComparer.Ordinal).ToList();
        if (otherIds.Any(id => string.Equals(id, currentUserId, StringComparison.Ordinal)))
        {
            throw new CustomException("Cannot DM yourself.", (IEnumerable<string>?)null, System.Net.HttpStatusCode.BadRequest);
        }

        if (otherIds.Count == 1)
        {
            // Two-person DM — deterministic lookup via DirectKey.
            var (lo, hi) = string.CompareOrdinal(currentUserId, otherIds[0]) < 0
                ? (currentUserId, otherIds[0])
                : (otherIds[0], currentUserId);
            var directKey = $"{lo}:{hi}";

            var existing = await db.Channels
                .FirstOrDefaultAsync(c => c.Type == ChannelType.DirectMessage && c.DirectKey == directKey, cancellationToken)

View on GitHub (pinned to 3f2959e683)