{"record":{"id":"f7a0fe938f9de746","repo":"fullstackhero/dotnet-starter-kit","slug":"the-email-for-0-is-already-confirmed","errorCode":null,"errorMessage":"The email for {0} is already confirmed.","messagePattern":"The email for (.+?) is already confirmed\\.","errorType":"exception","errorClass":"CustomException","httpStatus":400,"severity":"warning","filePath":"src/Modules/Identity/Modules.Identity/Services/UserRegistrationService.cs","lineNumber":130,"sourceCode":"                CultureInfo.InvariantCulture,\n                \"An error occurred while confirming the email for {0}: {1}\",\n                user.Email,\n                string.Join(\"; \", result.Errors.Select(e => e.Description))));\n        }\n    }\n\n    public async Task ResendConfirmationEmailAsync(string userId, string origin, CancellationToken cancellationToken = default)\n    {\n        EnsureValidTenant();\n\n        var user = await userManager.Users\n            .Where(u => u.Id == userId)\n            .FirstOrDefaultAsync(cancellationToken)\n            ?? throw new NotFoundException($\"User {userId} was not found.\");\n\n        if (user.EmailConfirmed)\n        {\n            throw new CustomException(string.Format(\n                CultureInfo.InvariantCulture,\n                \"The email for {0} is already confirmed.\",\n                user.Email));\n        }\n\n        await SendConfirmationEmailAsync(user, origin, cancellationToken);\n    }\n\n    public async Task<string> ConfirmPhoneNumberAsync(string userId, string code, CancellationToken cancellationToken = default)\n    {\n        EnsureValidTenant();\n\n        var user = await userManager.Users\n            .Where(u => u.Id == userId && !u.PhoneNumberConfirmed)\n            .FirstOrDefaultAsync(cancellationToken);\n\n        _ = user ?? throw new CustomException(\"An error occurred while confirming phone number.\");\n","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Services/UserRegistrationService.cs#L112-L148","documentation":"Thrown as a CustomException when ResendConfirmationEmailAsync is called for a user whose EmailConfirmed is already true. Resending a confirmation email to an already-confirmed account is treated as a client-side error (400-style) rather than a silent no-op — unlike AdminConfirmEmailAsync which is idempotent. The intent is to stop unnecessary emails.","triggerScenarios":"Double-click on 'resend confirmation' after the user already clicked the emailed link; calling resend from an admin flow without checking confirmation status; a resend request racing with the user's own email confirmation.","commonSituations":"User confirms via email then clicks resend in an old browser tab; automated retry job resending to already-confirmed users; frontend not refreshing user state after confirmation.","solutions":["Check the user's emailConfirmed status in the UI before offering the resend action","Treat this 400 as success in the client (email is already confirmed) and show an informative message","Disable the resend button after the first click and poll confirmation status","Debounce/deduplicate resend calls in the frontend"],"exampleFix":"// before\nawait service.ResendConfirmationEmailAsync(userId, origin, ct);\n// after\ntry\n{\n    await service.ResendConfirmationEmailAsync(userId, origin, ct);\n}\ncatch (CustomException) when (emailAlreadyConfirmed)\n{\n    toast.Info(\"This email is already confirmed. You can sign in.\");\n}","handlingStrategy":"try-catch","validationCode":"var confirmed = await userManager.Users.Where(u => u.Id == userId).Select(u => u.EmailConfirmed).FirstOrDefaultAsync(); if (confirmed) return;","typeGuard":"if (user?.EmailConfirmed == true) return Results.Ok(\"already confirmed\");","tryCatchPattern":"catch (CustomException) when (message.Contains(\"already confirmed\")) { return Results.Ok(\"Email is already confirmed.\"); }","preventionTips":["Hide the resend action once EmailConfirmed is true in the UI","Disable resend buttons after click (debounce)","Poll confirmation status after sending the email instead of blind retries"],"tags":["identity","duplicate-operation","email-confirmation"],"backgroundTag":"invalid-state-transition","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"}