fullstackhero/dotnet-starter-kit · error · NotFoundException
user not found
Error message
user not found
What it means
GetAsync throws NotFoundException('user not found') when no user with the given userId exists in the request's resolved tenant (query over userManager.Users finds nothing). It is a read-path 404: the profile endpoint was called with an id that doesn't match any row in the current tenant's user table.
Solutions
- Confirm the userId exists in the current tenant (query AspNetUsers directly).
- Check tenant resolution — the user may live in a different tenant than the request resolved to.
- Refresh any client-side cached user ids after database resets or migrations.
- Fix the caller to use the authenticated user's own id (the endpoint reads the current user's record).
Defensive patterns
Strategy: try-catch
Validate before calling
const res = await fetch(`/api/users/${id}/exists`);
if (!res.ok) return null; // avoid calling GetAsync for a non-existent id Type guard
function isUserDto(x): x is UserDto { return !!x && typeof x === 'object' && typeof (x as any).id === 'string'; } Try / catch
try { const user = await getProfile(userId); }
catch (e) { if (e.status === 404) { showNotFound(userId); } else { throw e; } } Prevention
- Use the authenticated principal's id instead of client-stored ids where possible.
- Invalidate cached user references after database resets.
- Confirm tenant headers are sent on every profile call.
- Handle 404 explicitly in profile UIs — it is an expected outcome.
When it happens
Trigger: GET profile with a userId that doesn't exist, was deleted, or belongs to a different tenant (tenant filter hides it).
Common situations: Client caching stale user ids after a DB re-seed; cross-tenant lookup attempts; typos or id mismatches in the caller's data; tenant context resolving to the wrong tenant so the row is filtered out.
Understand the failure class
Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/3c73bda2f52b84be.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Services/UserProfileService.cs:37
UserManager<FshUser> userManager,
SignInManager<FshUser> signInManager,
IStorageService storageService,
IMultiTenantContextAccessor<AppTenantInfo> multiTenantContextAccessor,
IOptions<OriginOptions> originOptions,
IHttpContextAccessor httpContextAccessor) : IUserProfileService
{
private readonly Uri? _originUrl = originOptions.Value.OriginUrl;
public async Task<UserDto> GetAsync(string userId, CancellationToken cancellationToken)
{
// Relies on Finbuckle's tenant filter — callers can only ever read
// their own user record, which is in the request's resolved tenant.
var user = await userManager.Users
.AsNoTracking()
.Where(u => u.Id == userId)
.FirstOrDefaultAsync(cancellationToken);
_ = user ?? throw new NotFoundException("user not found");
return new UserDto
{
Id = user.Id,
Email = user.Email,
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
ImageUrl = ResolveImageUrl(user.ImageUrl),
IsActive = user.IsActive,
EmailConfirmed = user.EmailConfirmed,
PhoneNumber = user.PhoneNumber,
TwoFactorEnabled = user.TwoFactorEnabled,
};
}
public Task<int> GetCountAsync(CancellationToken cancellationToken) =>
userManager.Users.AsNoTracking().CountAsync(cancellationToken);View on GitHub (pinned to 3f2959e683)