fullstackhero/dotnet-starter-kit · error · CustomException
An error occurred while confirming phone number.
Error message
An error occurred while confirming phone number.
What it means
A deliberately vague CustomException thrown by ConfirmPhoneNumberAsync when no unconfirmed-phone user is found for the given userId. The query filters u.Id == userId && !u.PhoneNumberConfirmed, so it fires both when the user doesn't exist and when the phone number is already confirmed. The generic message avoids leaking account existence.
Solutions
- Check whether the phone is already confirmed and show 'already confirmed' instead of retrying
- Verify the userId is correct and belongs to the current tenant
- Request a fresh phone-confirmation code if the previous flow already completed
- Ensure the code token hasn't expired and resend the SMS if needed
Example fix
// before
var ok = await service.ConfirmPhoneNumberAsync(userId, code, ct);
// after
var user = await userManager.Users.FirstOrDefaultAsync(u => u.Id == userId, ct);
if (user?.PhoneNumberConfirmed == true) return Results.Ok("Phone already confirmed.");
if (user is null) return Results.NotFound();
var ok = await service.ConfirmPhoneNumberAsync(userId, code, ct); Defensive patterns
Strategy: validation
Validate before calling
var user = await userManager.Users.FirstOrDefaultAsync(u => u.Id == userId); var eligible = user is not null && !user.PhoneNumberConfirmed;
Type guard
if (user is null || user.PhoneNumberConfirmed) return Results.BadRequest("User not found or phone already confirmed."); Try / catch
catch (CustomException ex) { return Results.BadRequest(new { error = "phone-confirm-failed", hint = "Check userId, tenant, and whether the phone is already confirmed." }); } Prevention
- Remember this error conflates 'not found' and 'already confirmed' — check both client-side
- Verify tenant context before calling
- Only submit the code once; regenerate for retries
When it happens
Trigger: ConfirmPhoneNumberAsync called with an unknown userId; the user's phone is already confirmed (filtered out by !PhoneNumberConfirmed); wrong tenant so the user isn't visible.
Common situations: User submits the phone code twice; code email/SMS link reused after success; userId from a different tenant; test fixture with unseeded users.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- An error occurred while confirming phone number
- Group with ID ' ' not found.
- Users not found
- Group with name ' ' already exists.
- Roles not found
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/ddf8c9b59dcd778a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Services/UserRegistrationService.cs:147
{
throw new CustomException(string.Format(
CultureInfo.InvariantCulture,
"The email for {0} is already confirmed.",
user.Email));
}
await SendConfirmationEmailAsync(user, origin, cancellationToken);
}
public async Task<string> ConfirmPhoneNumberAsync(string userId, string code, CancellationToken cancellationToken = default)
{
EnsureValidTenant();
var user = await userManager.Users
.Where(u => u.Id == userId && !u.PhoneNumberConfirmed)
.FirstOrDefaultAsync(cancellationToken);
_ = user ?? throw new CustomException("An error occurred while confirming phone number.");
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
var result = await userManager.ChangePhoneNumberAsync(user, user.PhoneNumber!, code);
return result.Succeeded
? string.Format(CultureInfo.InvariantCulture, "Phone number {0} confirmed successfully.", user.PhoneNumber)
: throw new CustomException(string.Format(CultureInfo.InvariantCulture, "An error occurred while confirming phone number {0}", user.PhoneNumber));
}
private void EnsureValidTenant()
{
if (string.IsNullOrWhiteSpace(multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id))
{
throw new UnauthorizedException("invalid tenant");
}
}
private static string ExtractEmailFromPrincipal(ClaimsPrincipal principal)View on GitHub (pinned to 3f2959e683)