aspnetboilerplate/aspnetboilerplate · error · UserFriendlyException

InvalidTenancyName

Error message

InvalidTenancyName

What it means

AbpTenantManager.ValidateTenancyNameAsync checks the tenancy name against AbpTenant<TUser>.TenancyNameRegex (by default ^[a-zA-Z][a-zA-Z0-9_-]{1,31}$ i.e. must start with a letter, be 2-32 chars of letters/digits/underscore/dash). If the name doesn't match, it throws UserFriendlyException with the localized 'InvalidTenancyName' message. This is called from ValidateTenantAsync during CreateAsync/UpdateAsync.

Solutions

  1. Validate the tenancy name against TenancyNameRegex before calling CreateAsync/UpdateAsync and return a field-level validation error.
  2. Normalize user input: trim, remove spaces/special characters, convert to the allowed charset.
  3. If your project overrides TenancyNameRegex, ensure the new pattern matches your existing tenants before deploying.

Example fix

// before
await _tenantManager.CreateAsync(new Tenant(userInput, name)); // throws for "my company!"
// after
var tenancyName = Regex.Replace(userInput.Trim(), "[^a-zA-Z0-9_-]", "");
if (!Regex.IsMatch(tenancyName, AbpTenant<CartItem>.TenancyNameRegex))
    return BadRequest("Tenancy name must start with a letter and be 2-32 chars (letters, digits, - or _).");
await _tenantManager.CreateAsync(new Tenant(tenancyName, name));
Defensive patterns

Strategy: validation

Validate before calling

bool valid = Regex.IsMatch(tenancyName ?? "", AbpTenant<AbpUserBase>.TenancyNameRegex);
if (!valid) throw new UserFriendlyException("Invalid tenancy name: must start with a letter, 2-32 chars of letters/digits/-/_.");

Type guard

bool IsValidTenancyName(string name) =>
    !string.IsNullOrEmpty(name) && Regex.IsMatch(name, AbpTenant<AbpUserBase>.TenancyNameRegex);

Try / catch

try { await _tenantManager.CreateAsync(tenant); }
catch (UserFriendlyException ex) when (ex.Message == _l("InvalidTenancyName")) { ModelState.AddModelError("TenancyName", ex.Message); return View(model); }

Prevention

When it happens

Trigger: Creating or updating a tenant (CreateAsync/UpdateAsync → ValidateTenantAsync) whose TenancyName fails the regex: empty string, contains spaces or special characters, starts with a digit, or is longer than 32 characters.

Common situations: Sign-up forms that don't validate the tenant name client-side (allowing spaces or dots like 'my.company'); tenants named with uppercase/convention-violating input; customized TenancyNameRegex in a newer version breaking previously valid names; white-label imports with legacy naming.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of aspnetboilerplate/aspnetboilerplate@2323c13a15 (2026-09-08). Data as JSON: /api/errors/19381b7c15bea74f. Report an issue: GitHub.

Appendix: source

Thrown at src/Abp.Zero.Common/MultiTenancy/AbpTenantManager.cs:428

                }
            });
        }

        protected virtual async Task ValidateTenantAsync(TTenant tenant)
        {
            await ValidateTenancyNameAsync(tenant.TenancyName);
        }

        protected virtual void ValidateTenant(TTenant tenant)
        {
            ValidateTenancyName(tenant.TenancyName);
        }

        protected virtual Task ValidateTenancyNameAsync(string tenancyName)
        {
            if (!Regex.IsMatch(tenancyName, AbpTenant<TUser>.TenancyNameRegex))
            {
                throw new UserFriendlyException(L("InvalidTenancyName"));
            }

            return Task.FromResult(0);
        }

        protected virtual void ValidateTenancyName(string tenancyName)
        {
            if (!Regex.IsMatch(tenancyName, AbpTenant<TUser>.TenancyNameRegex))
            {
                throw new UserFriendlyException(L("InvalidTenancyName"));
            }
        }

        protected virtual string L(string name)
        {
            return LocalizationManager.GetString(LocalizationSourceName, name);
        }

View on GitHub (pinned to 2323c13a15)