fullstackhero/dotnet-starter-kit · error · UnauthorizedException
no current user
Error message
no current user
What it means
EditMessageCommandHandler throws UnauthorizedException("no current user") when currentUser.GetUserId() yields Guid.Empty — no authenticated identity on the request. It guards the top of Handle before any lookup. Results in HTTP 401 via the shared exception middleware.
Solutions
- Attach a valid bearer token to the edit request; refresh expired tokens.
- Verify [Authorize] and UseAuthentication/UseAuthorization are configured for the endpoint.
- Ensure auth state is ready in the UI before enabling message editing.
- In tests, mock ICurrentUser.GetUserId() to return a non-empty Guid.
Example fix
// before var userId = currentUser.GetUserId(); // Guid.Empty in test // after currentUserMock.GetCurrentUserId().Returns(Guid.NewGuid()); // authenticated test context
Defensive patterns
Strategy: try-catch
Validate before calling
if (!auth.user?.id) return; // no identity — don't attempt the edit
Type guard
function hasUserId(u: unknown): u is { id: string } {
return typeof u === "object" && u !== null && typeof (u as { id?: unknown }).id === "string"
&& (u as { id: string }).id !== "00000000-0000-0000-0000-000000000000";
} Try / catch
try {
await api.editMessage(messageId, body);
} catch (e) {
if (e.status === 401) { await reauth(); }
else throw e;
} Prevention
- Require a resolved auth state before enabling message editing UI.
- Refresh tokens before they expire.
- Mock ICurrentUser with a real Guid in handler tests.
- Keep authentication middleware ordered before endpoints.
When it happens
Trigger: PATCH/PUT edit-message call with missing/expired JWT; handler invoked from a job or test without an authenticated ICurrentUser; SignalR-triggered edit outside an HTTP auth context.
Common situations: Frontend fired the edit before login completed or after token expiry; endpoint missing [Authorize]; tests using a bare handler with default mocks (Guid.Empty).
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/7f7a1aafccb33449.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Messages/EditMessage/EditMessageCommandHandler.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.EditMessage;
public sealed class EditMessageCommandHandler(
ChatDbContext db,
ICurrentUser currentUser,
IHubContext<AppHub> hub)
: ICommandHandler<EditMessageCommand, Unit>
{
public async ValueTask<Unit> Handle(EditMessageCommand 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.");
// Verify membership through the parent channel (don't leak existence to non-members).
var channel = await db.Channels.FirstOrDefaultAsync(c => c.Id == message.ChannelId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException("Message not found.");
channel.RequireMember(currentUserId);
message.Edit(cmd.Body, currentUserId); // domain enforces author-only
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
await hub.Clients.Group($"channel:{channel.Id}")
.SendAsync("ChatMessageEdited", message.ToDto(), cancellationToken)
.ConfigureAwait(false);View on GitHub (pinned to 3f2959e683)