OrchardCMS/OrchardCore · error · ArgumentException
Content type name must start with a letter
Error message
Content type name must start with a letter
What it means
ContentTypeDefinitionBuilder.Build throws ArgumentException when the content type name's first character is not a letter. Type names are used as safe identifiers across indexes, routing and display binding.
Solutions
- Prefix the type name with a letter, e.g. "Product2024" instead of "2024Product".
- Validate before building: char.IsLetter(name[0]).
- Ensure the name is non-null and non-empty before Build().
Example fix
// before
builder.Named("2FACode").Build(); // throws
// after
builder.Named("Code2FA").Build(); Defensive patterns
Strategy: validation
Validate before calling
bool IsValidTypeName(string name) =>
!string.IsNullOrEmpty(name) && char.IsLetter(name[0]); Try / catch
try
{
var typeDef = builder.Build();
}
catch (ArgumentException e)
{
_logger.LogError(e, "Invalid content type name '{Name}'", name);
} Prevention
- Validate type names before AlterTypeDefinitionAsync in migrations.
- Prefix generated type names with a letter when sources start with digits.
- Add recipes/migration tests covering type name edge cases.
When it happens
Trigger: builder.Named("1Product") / Named("") then Build(); AlterTypeDefinitionAsync migrations generating type names from data starting with digits; null/empty name.
Common situations: Type names derived from database table or entity names with numeric prefixes, recipes with invalid type names, programmatic type creation from external catalogs.
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
- Content part name must start with a letter
- Content part name contains invalid characters
- Content field name must start with a letter
- Content field name contains invalid characters
- Content type name contains invalid characters
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/4302c576e0df7f91.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore/OrchardCore.ContentManagement.Abstractions/Metadata/Builders/ContentTypeDefinitionBuilder.cs:43
if (existing == null)
{
_parts = [];
_settings = [];
}
else
{
_name = existing.Name;
_displayName = existing.DisplayName;
_parts = existing.Parts.ToList();
_settings = existing.Settings.Clone();
}
}
public ContentTypeDefinition Build()
{
if (!char.IsLetter(_name[0]))
{
throw new ArgumentException("Content type name must start with a letter", "name");
}
if (!string.Equals(_name, _name.ToSafeName(), StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("Content type name contains invalid characters", "name");
}
if (_name.IsReservedContentName())
{
throw new ArgumentException("Content type name is reserved for internal use", "name");
}
return new ContentTypeDefinition(_name, _displayName, _parts, _settings);
}
[Obsolete("This method has been deprecated, please use WithName() instead.")]
public ContentTypeDefinitionBuilder Named(string name) => WithName(name);
public ContentTypeDefinitionBuilder WithName(string name)
{View on GitHub (pinned to 4306c0717f)