fullstackhero/dotnet-starter-kit · error · CustomException

Unable to register the user.

Error message

Unable to register the user.

What it means

Thrown by CreateUserWithPasswordAsync when ASP.NET Identity's UserManager.CreateAsync returns a non-succeeded result. It deliberately surfaces Identity's per-property failure descriptions (duplicate email/username, password policy violations, etc.) as a 400 BadRequest instead of a 500, since these are client-input problems.

Solutions

  1. Read the errorDescriptions array in the response — it lists the exact Identity failure reasons.
  2. Verify the email/username is not already registered before submitting, or use the forgot-password flow for existing accounts.
  3. Bring the password in line with the configured IdentityOptions.Password policy for this environment.
  4. If seeding, make registration idempotent: check for existing user first instead of re-creating.

Example fix

// before: blind create fails on duplicates
await registrationService.CreateUserWithPasswordAsync(request, ct);
// after: pre-check then create
var existing = await userManager.FindByEmailAsync(request.Email);
if (existing is not null) throw new CustomException("Email already registered.", Array.Empty<string>(), HttpStatusCode.BadRequest);
await registrationService.CreateUserWithPasswordAsync(request, ct);
Defensive patterns

Strategy: validation

Validate before calling

const emailRe = /^[^@\s]+@[^@\s]+$/;
if (!emailRe.test(payload.email)) throw new Error("Invalid email");
if (payload.password.length < 8 || !/[A-Z]/.test(payload.password) || !/\d/.test(payload.password))
  throw new Error("Password must be 8+ chars with upper case and digit");

Try / catch

try { await register(payload); } catch (e) {
  if (e.status === 400 && Array.isArray(e.errors)) showFieldErrors(e.errors); // per-reason Identity messages
  else throw e;
}

Prevention

When it happens

Trigger: Calling the user-registration endpoint with an email or username already taken, a password that fails the configured Identity password policy (length, complexity, uniqueness), or any other rule enforced by UserManager (e.g. RequireUniqueEmail).

Common situations: Seeding scripts re-registering the same admin twice; frontends not pre-validating password rules that differ from defaults; duplicate signup attempts racing on the same email; environments where password options were tightened after users existed.

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/7ef44c83f6e80682. Report an issue: GitHub.

Appendix: source

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

        {
            Email = email,
            FirstName = firstName,
            LastName = lastName,
            UserName = userName,
            PhoneNumber = phoneNumber,
            IsActive = true,
            EmailConfirmed = false,
            PhoneNumberConfirmed = false,
        };

        var result = await userManager.CreateAsync(user, password);
        if (!result.Succeeded)
        {
            // Identity create failures (duplicate email/username, password policy, …) are
            // client-input errors, not server faults — surface them as 400 with the specific
            // reasons so the caller sees *why* registration failed, not a bare 500.
            var errors = result.Errors.Select(error => error.Description).ToList();
            throw new CustomException(
                "Unable to register the user.",
                errors,
                HttpStatusCode.BadRequest);
        }

        return user;
    }

    private async Task AssignDefaultRoleAndGroupsAsync(
        FshUser user,
        string source,
        CancellationToken cancellationToken = default)
    {
        await userManager.AddToRoleAsync(user, RoleConstants.Basic);

        var defaultGroups = await db.Groups
            .AsNoTracking()
            .Where(g => g.IsDefault && !g.IsDeleted)

View on GitHub (pinned to 3f2959e683)