fullstackhero/dotnet-starter-kit · error · CustomException
An error occurred while confirming E-Mail.
Error message
An error occurred while confirming E-Mail.
What it means
ConfirmEmailAsync throws CustomException('An error occurred while confirming E-Mail.') when no unconfirmed user matching the given userId exists (the query filters to Id == userId && !EmailConfirmed). It is deliberately vague to avoid leaking whether an account exists or is already confirmed.
Solutions
- If the account already works, just sign in — the error often means confirmation already completed.
- Request a fresh confirmation email to get a new valid userId+code pair.
- Verify the confirmation link points at the correct tenant host so the user row is visible.
- Re-send registration/confirmation if the DB was re-seeded and the old link's user no longer exists.
Defensive patterns
Strategy: try-catch
Validate before calling
// client-side: only fire confirmation once, and detect already-confirmed
const { data: me } = await tryGetCurrentUser();
if (me?.emailConfirmed) redirect('/login'); Try / catch
try { await confirmEmail(userId, code); }
catch (e) { if (e.status === 400 && /confirming E-Mail/.test(e.detail)) { promptLogin('Account may already be confirmed.'); } else { throw e; } } Prevention
- Make confirmation links single-use in the UI (disable after click).
- Generate confirmation URLs against the correct tenant host.
- Re-send confirmation emails rather than reusing old links.
- Handle the vague 400 by offering a sign-in attempt first — already-confirmed is the most common cause.
When it happens
Trigger: Clicking an email-confirmation link after the account was already confirmed; a tampered or mismatched userId in the link; the user row being deleted; tenant resolution directing the query to a tenant without that user.
Common situations: Users double-clicking confirmation links or reusing an old email; expired/stale links from before a database re-seed; wrong tenant host in the confirmation URL so the user isn't found in that tenant's store.
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/26ef4be3b168172c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Services/UserRegistrationService.cs:82
ValidatePasswordMatch(password, confirmPassword);
var user = await CreateUserWithPasswordAsync(firstName, lastName, email, userName, password, phoneNumber);
await AssignDefaultRoleAndGroupsAsync(user, "System", cancellationToken);
await SendConfirmationEmailAsync(user, origin, cancellationToken);
await PublishUserRegisteredAsync(user, "Identity", cancellationToken);
return user.Id;
}
public async Task<string> ConfirmEmailAsync(string userId, string code, string tenant, CancellationToken cancellationToken)
{
EnsureValidTenant();
var user = await userManager.Users
.Where(u => u.Id == userId && !u.EmailConfirmed)
.FirstOrDefaultAsync(cancellationToken);
_ = user ?? throw new CustomException("An error occurred while confirming E-Mail.");
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
var result = await userManager.ConfirmEmailAsync(user, code);
return result.Succeeded
? string.Format(CultureInfo.InvariantCulture, "Account Confirmed for E-Mail {0}. You can now use the /api/tokens endpoint to generate JWT.", user.Email)
: throw new CustomException(string.Format(CultureInfo.InvariantCulture, "An error occurred while confirming {0}", user.Email));
}
public async Task AdminConfirmEmailAsync(string userId, CancellationToken cancellationToken = default)
{
EnsureValidTenant();
var user = await userManager.Users
.Where(u => u.Id == userId)
.FirstOrDefaultAsync(cancellationToken)
?? throw new NotFoundException($"User {userId} was not found.");
View on GitHub (pinned to 3f2959e683)