{"record":{"id":"722b2982533e619d","repo":"fullstackhero/dotnet-starter-kit","slug":"user-not-found-userpasswordservice","errorCode":null,"errorMessage":"user not found","messagePattern":"user not found","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Services/UserPasswordService.cs","lineNumber":69,"sourceCode":"                [\"email\"] = email,\n                [\"tenant\"] = multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id,\n            });\n        var mailRequest = new MailRequest(\n            new Collection<string> { user.Email },\n            \"Reset Password\",\n            $\"Please reset your password using the following link: {resetPasswordUri}\");\n\n        jobService.Enqueue(() => mailService.SendAsync(mailRequest, CancellationToken.None));\n    }\n\n    public async Task ResetPasswordAsync(string email, string password, string token, CancellationToken cancellationToken)\n    {\n        EnsureValidTenant();\n\n        var user = await userManager.FindByEmailAsync(email);\n        if (user == null)\n        {\n            throw new NotFoundException(\"user not found\");\n        }\n\n        token = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(token));\n        var result = await userManager.ResetPasswordAsync(user, token, password);\n\n        if (!result.Succeeded)\n        {\n            var errors = result.Errors.Select(e => e.Description).ToList();\n            throw new CustomException(\"error resetting password\", errors);\n        }\n\n        // Raise domain event for password reset\n        var tenantId = multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id;\n        user.RecordPasswordChanged(wasReset: true, tenantId);\n        await db.SaveChangesAsync(cancellationToken);\n    }\n\n    public async Task ChangePasswordAsync(string password, string newPassword, string confirmNewPassword, string userId, CancellationToken cancellationToken = default)","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Services/UserPasswordService.cs#L51-L87","documentation":"ResetPasswordAsync throws NotFoundException when userManager.FindByEmailAsync(email) returns null, i.e. no user with that email exists in the current tenant. The reset cannot proceed without the user record that owns the password.","triggerScenarios":"Calling ResetPasswordAsync(email, token, password, ...) with an email that has no matching FshUser — wrong email typed, user deleted, or the user exists in a different tenant.","commonSituations":"Client mistyped the email; calling reset in the wrong tenant context (users are tenant-scoped); user was removed between requesting the reset token and submitting it; test data never seeded the user.","solutions":["Verify the email address is spelled correctly and matches the registered user","Ensure the request resolves to the same tenant the user belongs to (send the tenant identifier)","Check the user row exists in the AspNetUsers table for that tenant/email","If the user was deleted, re-register the account before resetting the password"],"exampleFix":"var user = await userManager.FindByEmailAsync(email);\nif (user is null) return Results.NotFound($\"no user with email {email}\");\nawait passwordService.ResetPasswordAsync(email, token, newPassword, ct);","handlingStrategy":"validation","validationCode":"var normalized = email?.Trim().ToLowerInvariant();\nif (string.IsNullOrWhiteSpace(normalized) || !new EmailAddressAttribute().IsValid(normalized))\n    return Results.BadRequest(\"A valid email is required.\");\nvar exists = await userManager.Users.AnyAsync(u => u.NormalizedEmail == userManager.NormalizeEmail(normalized));\nif (!exists) return Results.NotFound(\"No account found for this email in the current tenant.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    await passwordService.ResetPasswordAsync(email, token, newPassword, ct);\n}\ncatch (NotFoundException)\n{\n    return Results.NotFound(\"No account found for this email in the current tenant.\");\n}","preventionTips":["Confirm the user exists in the target tenant before sending reset links","Normalize/trim email input client-side","Remember users are tenant-scoped — same email may exist only in another tenant"],"tags":["identity","password-reset","not-found"],"backgroundTag":"user-not-found","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}