fullstackhero/dotnet-starter-kit · warning · NotFoundException

User not found.

Error message

User {userId} not found.

What it means

DisableTwoFactorCommandHandler throws NotFoundException when UserManager.FindByIdAsync returns null for the id taken from the current user's claims. This means the JWT identifies a user that no longer exists in the identity database.

Solutions

  1. Re-authenticate to get a token bound to an existing user
  2. Verify the JWT's sub/nameidentifier claim matches a row inAspNetUsers (dotnet: SELECT "Id" FROM "AspNetUsers" WHERE "Id" = '<claim>')
  3. Confirm the API is connected to the intended database/environment
  4. If users are soft-deleted, decide whether FindByIdAsync should filter them and return a clearer message

Example fix

// before
var user = await _userManager.FindByIdAsync(userId)
    ?? throw new NotFoundException($"User {userId} not found.");
// after
if (await _userManager.FindByIdAsync(userId) is not User user)
{
    _logger.LogWarning("Disable 2FA rejected: user {UserId} from token no longer exists", userId);
    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.disableTwoFactor(cmd);
} catch (e) {
  if (e.status === 404 && /User .* not found/.test(e.message)) {
    clearSession();
    throw new SessionExpiredError();
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling disable-2FA with a valid but stale token issued for a deleted user; a token whose nameidentifier claim points to a user in a different database/environment; test tokens with fabricated user ids.

Common situations: User account deleted or hard-removed while an access token was still valid; pointing the API at a fresh/migrated database while reusing old tokens; multi-environment token reuse (dev token against prod DB).

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

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Features/v1/TwoFactor/Disable/DisableTwoFactorCommandHandler.cs:34

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

    public async ValueTask<bool> Handle(
        DisableTwoFactorCommand 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.");

        // Require current password so a stolen access token alone can't downgrade
        // account security.
        if (!await _userManager.CheckPasswordAsync(user, command.CurrentPassword))
        {
            throw new UnauthorizedException("Current password is incorrect.");
        }

        await _userManager.SetTwoFactorEnabledAsync(user, false);
        await _userManager.ResetAuthenticatorKeyAsync(user);
        return true;
    }
}

View on GitHub (pinned to 3f2959e683)