fullstackhero/dotnet-starter-kit · error · UnauthorizedException
no current user
Error message
no current user
What it means
DiscoverChannelsQueryHandler throws UnauthorizedException when currentUser.GetUserId() returns Guid.Empty — discovery is scoped to the calling user (it excludes their existing memberships), so an anonymous request cannot be served.
Solutions
- Attach a valid bearer token to the discovery request
- Implement 401 handling: refresh token and retry once
- In tests, mock ICurrentUser.GetUserId() to return a real Guid
Example fix
// before
const res = await fetch('/api/v1/channels/discover'); // 401 no current user
// after
const res = await apiFetch('/api/v1/channels/discover'); // apiFetch attaches JWT and handles 401 refresh 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 discover(); }
catch (UnauthorizedException) { /* refresh token and retry once */ } Prevention
- Never call discovery endpoints anonymously
- Centralize auth in apiFetch so JWT is always attached
- Retry once after token refresh on 401
When it happens
Trigger: GET channel discovery without a valid JWT, expired token, or calling the query handler directly in tests with an unauthenticated ICurrentUser.
Common situations: Token expired while browsing; missing Authorization header on a 'public-looking' endpoint the developer assumed was anonymous; tests forgetting auth setup.
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/446229cf1618e9a7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Channels/DiscoverChannels/DiscoverChannelsQueryHandler.cs:23
using FSH.Modules.Chat.Contracts.v1.Queries;
using FSH.Modules.Chat.Data;
using FSH.Modules.Chat.Domain;
using FSH.Modules.Chat.Features.v1.Internal;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Chat.Features.v1.Channels.DiscoverChannels;
public sealed class DiscoverChannelsQueryHandler(
ChatDbContext db,
ICurrentUser currentUser)
: IQueryHandler<DiscoverChannelsQuery, ReadOnlyCollection<ChannelDto>>
{
public async ValueTask<ReadOnlyCollection<ChannelDto>> Handle(DiscoverChannelsQuery q, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(q);
var userId = currentUser.GetUserId();
if (userId == Guid.Empty) throw new UnauthorizedException("no current user");
var currentUserId = userId.ToString();
int page = Math.Max(1, q.Page);
int pageSize = Math.Clamp(q.PageSize, 1, 200);
var query = db.Channels.AsNoTracking()
.Where(c => c.Type == ChannelType.Channel
&& !c.IsPrivate
&& !c.Members.Any(m => m.UserId == currentUserId));
if (!string.IsNullOrWhiteSpace(q.Search))
{
var term = q.Search.Trim();
query = query.Where(c =>
EF.Functions.ILike(c.Name!, $"%{term}%")
|| EF.Functions.ILike(c.Slug!, $"%{term}%"));
}
View on GitHub (pinned to 3f2959e683)