fullstackhero/dotnet-starter-kit · error · UnauthorizedException
no current user
Error message
no current user
What it means
ArchiveChannelCommandHandler throws UnauthorizedException when currentUser.GetUserId() returns Guid.Empty, i.e. no authenticated user is on the request. Archiving requires a caller both for the RequireAdmin check and audit attribution.
Solutions
- Send a valid non-expired bearer token with the request
- Handle 401 at the client by refreshing/re-authenticating
- In tests, mock ICurrentUser.GetUserId() to return a real Guid
Example fix
// before currentUser.GetUserId().Returns(Guid.Empty); // 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 handler.Handle(cmd, ct); }
catch (UnauthorizedException) { /* return 401 / re-authenticate */ } Prevention
- Ensure JWT attached to archive requests
- Handle token expiry proactively
- Stub ICurrentUser in tests
When it happens
Trigger: Calling the ArchiveChannel endpoint without a valid JWT, with an expired token or anonymous identity, or invoking the handler in tests without a mocked ICurrentUser.
Common situations: Client kept calling after token expiry; missing Authorization header; integration test forgot to authenticate the HttpClient.
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/da42844a292220bc.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Channels/ArchiveChannel/ArchiveChannelCommandHandler.cs:20
using FSH.Framework.Core.Exceptions;
using FSH.Modules.Chat.Contracts.v1.Commands;
using FSH.Modules.Chat.Data;
using FSH.Modules.Chat.Features.v1.Internal;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Chat.Features.v1.Channels.ArchiveChannel;
public sealed class ArchiveChannelCommandHandler(
ChatDbContext db,
ICurrentUser currentUser)
: ICommandHandler<ArchiveChannelCommand, Unit>
{
public async ValueTask<Unit> Handle(ArchiveChannelCommand cmd, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(cmd);
var userId = currentUser.GetUserId();
if (userId == Guid.Empty) throw new UnauthorizedException("no current user");
var channel = await db.Channels.FirstOrDefaultAsync(c => c.Id == cmd.ChannelId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException("Channel not found.");
channel.RequireAdmin(userId.ToString());
// Explicit soft-delete (not db.Remove): removing the aggregate cascades Deleted onto
// the ChannelMember rows, which the audit interceptor does not rescue (they're FK
// children, not owned), so they'd be hard-deleted and lost on restore.
channel.Archive(userId.ToString());
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
return Unit.Value;
}
}
View on GitHub (pinned to 3f2959e683)