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
- Read the errorDescriptions array in the response — it lists the exact Identity failure reasons.
- Verify the email/username is not already registered before submitting, or use the forgot-password flow for existing accounts.
- Bring the password in line with the configured IdentityOptions.Password policy for this environment.
- 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
- Mirror the server's Identity password policy in client-side validation.
- Check email/username availability before final submit.
- Make seed scripts idempotent (skip existing users).
- Always read errorDescriptions in the 400 body — it names the exact failing rule.
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
- Passwords do not match.
- File exceeds max size of
- File exceeds max size of
- ValidationException(failures)
- A category cannot be its own parent.
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)