fullstackhero/dotnet-starter-kit · error · CustomException

Failed to create user from external principal.

Error message

Failed to create user from external principal.

What it means

Thrown as a CustomException (400) when userManager.CreateAsync fails while provisioning a local user from an external-auth principal. The message is generic on purpose; the specific Identity error descriptions (duplicate email/username, password policy, validator failures) are attached in the errors list. It means the external identity is valid but local account creation was rejected by ASP.NET Identity.

Solutions

  1. Inspect the errors array on the exception for the exact Identity reason
  2. If duplicate email, route the user to the external-login linking flow (sign in with password, then link provider) instead of auto-creating
  3. Adjust generated userName/email normalization to avoid collisions (e.g. append provider id)
  4. Review custom IUserValidator/IEmailValidator registrations for overly strict rules

Example fix

// before
var user = await userRegistrationService.GetOrCreateFromPrincipalAsync(principal, provider);
// after
try
{
    var user = await userRegistrationService.GetOrCreateFromPrincipalAsync(principal, provider);
}
catch (CustomException ex) when (ex.Errors?.Any(e => e.Contains("already taken")) == true)
{
    return Results.Conflict("An account with this email exists. Sign in with your password to link the provider.");
}
Defensive patterns

Strategy: try-catch

Validate before calling

var email = principal.FindFirstValue(ClaimTypes.Email); var exists = await userManager.Users.AnyAsync(u => u.NormalizedEmail == email!.ToUpperInvariant());

Type guard

bool CanCreate(string email) => !string.IsNullOrWhiteSpace(email) && email.Contains('@');

Try / catch

catch (CustomException ex) when (ex.Errors?.Any(e => e.Contains("already")) == true) { return Results.Conflict("Account exists — sign in and link the provider instead."); }

Prevention

When it happens

Trigger: Signing in with an external provider whose email already belongs to an existing local account (duplicate username/email); custom user validators failing; normalized username collisions.

Common situations: User first registered with password, later tries Google sign-in with the same email; two providers issuing the same email; username generated from email exceeding length limits; custom IUserValidator misconfigured.

Related errors


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

Appendix: source

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

        userName = await EnsureUniqueUserNameAsync(userName);

        var user = new FshUser
        {
            Email = email,
            UserName = userName,
            FirstName = firstName,
            LastName = lastName,
            EmailConfirmed = true,
            PhoneNumberConfirmed = false,
            IsActive = true
        };

        var result = await userManager.CreateAsync(user);
        if (!result.Succeeded)
        {
            var errors = result.Errors.Select(e => e.Description).ToList();
            throw new CustomException(
                "Failed to create user from external principal.",
                errors,
                HttpStatusCode.BadRequest);
        }

        return user;
    }

    private static (string firstName, string lastName, string userName) ExtractUserInfoFromPrincipal(
        ClaimsPrincipal principal, string email)
    {
        var firstName = principal.FindFirstValue(ClaimTypes.GivenName)
            ?? principal.FindFirstValue("given_name")
            ?? string.Empty;

        var lastName = principal.FindFirstValue(ClaimTypes.Surname)
            ?? principal.FindFirstValue("family_name")
            ?? string.Empty;

View on GitHub (pinned to 3f2959e683)