fullstackhero/dotnet-starter-kit · error · CustomException

An error occurred while confirming

Error message

An error occurred while confirming {0}

What it means

ConfirmEmailAsync throws CustomException('An error occurred while confirming {0}') when UserManager.ConfirmEmailAsync returns a failed IdentityResult — the user was found and unconfirmed, but the provided code did not validate (wrong, expired, or corrupted token). The message includes the email to help the user retry.

Solutions

  1. Request a new confirmation email and use the freshest link/code.
  2. Ensure the full code is copied — check the email client didn't wrap or truncate the URL token.
  3. Avoid changing the password or security stamp between requesting and confirming; re-request if you did.
  4. Verify data-protection key persistence across instances/restarts so issued tokens remain valid.

Example fix

// caller: send the pristine code from the email link unchanged
// service: log identity errors for diagnosis
if (!result.Succeeded)
{
    var errors = string.Join("; ", result.Errors.Select(e => e.Description));
    logger.LogWarning("Email confirmation failed for {Email}: {Errors}", user.Email, errors);
    throw new CustomException(string.Format(CultureInfo.InvariantCulture, "An error occurred while confirming {0}", user.Email));
}
Defensive patterns

Strategy: retry

Validate before calling

// ensure the full code arrived intact
const code = new URLSearchParams(location.search).get('code');
if (!code || code.length < 20 || /[\s]/.test(code)) showError('Confirmation link appears incomplete — request a new email.');

Try / catch

try { await confirmEmail(userId, code); }
catch (e) { if (isBadRequest(e)) { await resendConfirmation(email); show('We sent a fresh confirmation link.'); } else { throw e; } }

Prevention

When it happens

Trigger: The confirmation code was Base64Url-decoded but rejected: token generated for a different purpose/user, invalidated by a security stamp change (password reset, profile update that rotates the stamp), tampering, or truncation of the code from the email client.

Common situations: Email clients wrapping/breaking the long code in the URL; user requested a password reset after the email was generated (stamp changed, old token invalid); link copy-paste losing characters; data-protection keys changed between environments invalidating old tokens.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/082725d15fb153c6. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Services/UserRegistrationService.cs:89

        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.");

        // Idempotent: a second confirm is a no-op rather than an error.
        if (user.EmailConfirmed)
        {
            return;
        }

        user.EmailConfirmed = true;

View on GitHub (pinned to 3f2959e683)