fullstackhero/dotnet-starter-kit · error · CustomException

error resetting password

Error message

error resetting password

What it means

ResetPasswordAsync throws CustomException('error resetting password') when userManager.ResetPasswordAsync fails (result.Succeeded == false). The Identity result errors (e.g. invalid/expired token, weak password) are attached to the exception as a list of descriptions.

Solutions

  1. Inspect the errors collection attached to the exception — it names the exact Identity failure
  2. Request a fresh password-reset token and retry promptly before it expires
  3. Ensure the token is sent exactly as generated (Base64Url encoded, no trimming/HTML unescaping)
  4. Choose a password satisfying the configured Identity password options

Example fix

// before: swallowing the detail
catch (CustomException) { return Results.BadRequest("reset failed"); }
// after
catch (CustomException ex) { return Results.BadRequest(new { ex.Message, errors = ex.Errors }); }
Defensive patterns

Strategy: try-catch

Validate before calling

var policyErrors = newPassword is null || newPassword.Length < 8
    ? new List<string> { "Password must be at least 8 characters." }
    : new List<string>();
if (policyErrors.Count > 0) return Results.BadRequest(policyErrors);

Try / catch

try
{
    await passwordService.ResetPasswordAsync(email, token, newPassword, ct);
}
catch (CustomException ex)
{
    return Results.BadRequest(new { message = ex.Message, identityErrors = ex.Errors });
}

Prevention

When it happens

Trigger: Submitting a reset token that is invalid, already used, or expired; new password violating the configured Identity password policy (length, complexity, reuse); token mangled by incorrect Base64Url encoding/decoding.

Common situations: Reset link older than the token lifetime; user requested multiple resets and used the older token; client double-encoded/decoded the Base64Url token; new password rejected by policy (e.g. too similar to old or missing special char).

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Services/UserPasswordService.cs:78

    }

    public async Task ResetPasswordAsync(string email, string password, string token, CancellationToken cancellationToken)
    {
        EnsureValidTenant();

        var user = await userManager.FindByEmailAsync(email);
        if (user == null)
        {
            throw new NotFoundException("user not found");
        }

        token = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(token));
        var result = await userManager.ResetPasswordAsync(user, token, password);

        if (!result.Succeeded)
        {
            var errors = result.Errors.Select(e => e.Description).ToList();
            throw new CustomException("error resetting password", errors);
        }

        // Raise domain event for password reset
        var tenantId = multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id;
        user.RecordPasswordChanged(wasReset: true, tenantId);
        await db.SaveChangesAsync(cancellationToken);
    }

    public async Task ChangePasswordAsync(string password, string newPassword, string confirmNewPassword, string userId, CancellationToken cancellationToken = default)
    {
        var user = await userManager.FindByIdAsync(userId);

        _ = user ?? throw new NotFoundException("user not found");

        var result = await userManager.ChangePasswordAsync(user, password, newPassword);

        if (!result.Succeeded)
        {

View on GitHub (pinned to 3f2959e683)