fullstackhero/dotnet-starter-kit · warning · NotFoundException

User not found.

Error message

User {userId} not found.

What it means

EnrollTwoFactorCommandHandler throws NotFoundException when the user id from the current principal cannot be resolved by UserManager.FindByIdAsync. The token is authenticated but references a user record that is absent from the identity store.

Solutions

  1. Re-authenticate so the token maps to an existing user
  2. Verify the user id claim exists inAspNetUsers in the database the API actually uses
  3. Confirm environment/config points at the intended DB (no dev/prod mixup)
  4. Return a clearer session-invalid message instead of a raw not-found if soft-deleted users should be treated as logged out

Example fix

// before
var user = await _userManager.FindByIdAsync(userId)
    ?? throw new NotFoundException($"User {userId} not found.");
// after
var user = await _userManager.FindByIdAsync(userId);
if (user is null)
{
    throw new UnauthorizedException("Session is no longer valid. Please sign in again.");
}
Defensive patterns

Strategy: try-catch

Validate before calling

const sub = parseJwt(accessToken)?.sub;
if (!sub) await reauthenticate();

Try / catch

try {
  await api.enrollTwoFactor();
} catch (e) {
  if (e.status === 404) { clearSession(); await reauthenticate(); return; }
  throw e;
}

Prevention

When it happens

Trigger: Enrolling with a token issued for a since-deleted user; a token whose nameidentifier claim belongs to another database/environment; test fixtures with invented user ids.

Common situations: Stale token after account deletion; switching connection strings/environments while reusing cached tokens; database re-seeded without re-issuing tokens.

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/bf19a7b653349ae3. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Features/v1/TwoFactor/Enroll/EnrollTwoFactorCommandHandler.cs:38

    public EnrollTwoFactorCommandHandler(UserManager<FshUser> userManager, ICurrentUser currentUser)
    {
        _userManager = userManager;
        _currentUser = currentUser;
    }

    public async ValueTask<TwoFactorEnrollmentResponse> Handle(
        EnrollTwoFactorCommand command, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(command);

        if (!_currentUser.IsAuthenticated())
        {
            throw new UnauthorizedException();
        }

        var userId = _currentUser.GetUserId().ToString();
        var user = await _userManager.FindByIdAsync(userId)
            ?? throw new NotFoundException($"User {userId} not found.");

        // Always reset so calling enroll twice rotates the secret — prevents stale codes
        // from a prior incomplete enrollment from silently succeeding.
        await _userManager.ResetAuthenticatorKeyAsync(user);
        var sharedKey = await _userManager.GetAuthenticatorKeyAsync(user)
            ?? throw new CustomException("Failed to generate authenticator key.");

        var email = user.Email ?? user.UserName ?? user.Id;
        var authenticatorUri = string.Format(
            System.Globalization.CultureInfo.InvariantCulture,
            "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6",
            UrlEncoder.Default.Encode(IssuerName),
            UrlEncoder.Default.Encode(email),
            sharedKey);

        return new TwoFactorEnrollmentResponse(sharedKey, authenticatorUri);
    }
}

View on GitHub (pinned to 3f2959e683)