OrchardCMS/OrchardCore · error · ArgumentException
Content type name contains invalid characters
Error message
Content type name contains invalid characters
What it means
ContentDefinitionService.AddTypeAsync validates the proposed content type name: it must start with an ASCII letter and must equal its ToSafeName() form (case-insensitive). If the name contains characters that would be altered or stripped by the safe-name normalization (spaces, digits leading, symbols, non-ASCII), an ArgumentException is thrown rather than silently mutating the caller's name.
Solutions
- Sanitize the name with the .ToSafeName() string extension before calling AddTypeAsync.
- Ensure the name starts with an ASCII letter and contains only letters, digits, and hyphens (no spaces or symbols).
- If the user-facing label differs from the technical name, pass a safe technical name and keep the label in the type's display name settings.
Example fix
// before
await contentDefinitionService.AddTypeAsync("Product Category", template => { });
// after
await contentDefinitionService.AddTypeAsync("Product Category".ToSafeName(), template => { }); // "ProductCategory" Defensive patterns
Strategy: validation
Validate before calling
// C#
static bool IsValidContentTypeName(string name) =>
!string.IsNullOrEmpty(name)
&& char.IsAsciiLetter(name[0])
&& string.Equals(name, name.ToSafeName(), StringComparison.OrdinalIgnoreCase);
// call AddTypeAsync only if IsValidContentTypeName(name) Type guard
static bool IsSafeName(string name) =>
!string.IsNullOrWhiteSpace(name) && name == name.ToSafeName(); Try / catch
try
{
await contentDefinitionService.AddTypeAsync(name, configure);
}
catch (ArgumentException ex)
{
logger.LogWarning(ex, "Invalid content type name: {Name}", name);
} Prevention
- Always run .ToSafeName() on names derived from user input before creating definitions.
- Start generated names with an ASCII letter; prefix with a letter if needed.
- Keep display labels separate from technical names.
When it happens
Trigger: Calling IContentDefinitionService.AddTypeAsync(name, ...) with a name that does not survive ToSafeName(), e.g. "My Type!", "1Widget", "Type-Ünï", or containing '/' or '.'.
Common situations: Deriving a type name from user input, a file name, or a display label; generating type names programmatically from localized strings; building type names by concatenation with separators.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Content type name must start with a letter
- The 'displayName' can't be null or empty.
- File path must be a non-empty string.
- Unable to create a safe index prefix for AI Search…
- Content part name must start with a letter
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/23ccfe234f5ca12c.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore.Modules/OrchardCore.ContentTypes/Services/ContentDefinitionService.cs:68
{
if (string.IsNullOrWhiteSpace(displayName))
{
throw new ArgumentException($"The '{nameof(displayName)}' can't be null or empty.", nameof(displayName));
}
if (string.IsNullOrWhiteSpace(name))
{
name = await GenerateContentTypeNameFromDisplayNameAsync(displayName);
}
else
{
if (!char.IsAsciiLetter(name[0]))
{
throw new ArgumentException("Content type name must start with a letter", nameof(name));
}
if (!string.Equals(name, name.ToSafeName(), StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("Content type name contains invalid characters", nameof(name));
}
}
while (await _contentDefinitionManager.LoadTypeDefinitionAsync(name) is not null)
{
name = VersionName(name);
}
var contentTypeDefinition = new ContentTypeDefinition(name, displayName);
await _contentDefinitionManager.StoreTypeDefinitionAsync(contentTypeDefinition);
// Ensure it has its own part.
await _contentDefinitionManager.AlterTypeDefinitionAsync(name, builder => builder.WithPart(name));
await _contentDefinitionManager.AlterTypeDefinitionAsync(name, cfg =>
{
cfg.Creatable()
.Draftable()View on GitHub (pinned to 4306c0717f)