{"record":{"id":"23ccfe234f5ca12c","repo":"OrchardCMS/OrchardCore","slug":"content-type-name-contains-invalid-characters-23ccfe","errorCode":null,"errorMessage":"Content type name contains invalid characters","messagePattern":"Content type name contains invalid characters","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore.Modules/OrchardCore.ContentTypes/Services/ContentDefinitionService.cs","lineNumber":68,"sourceCode":"    {\n        if (string.IsNullOrWhiteSpace(displayName))\n        {\n            throw new ArgumentException($\"The '{nameof(displayName)}' can't be null or empty.\", nameof(displayName));\n        }\n\n        if (string.IsNullOrWhiteSpace(name))\n        {\n            name = await GenerateContentTypeNameFromDisplayNameAsync(displayName);\n        }\n        else\n        {\n            if (!char.IsAsciiLetter(name[0]))\n            {\n                throw new ArgumentException(\"Content type name must start with a letter\", nameof(name));\n            }\n            if (!string.Equals(name, name.ToSafeName(), StringComparison.OrdinalIgnoreCase))\n            {\n                throw new ArgumentException(\"Content type name contains invalid characters\", nameof(name));\n            }\n        }\n\n        while (await _contentDefinitionManager.LoadTypeDefinitionAsync(name) is not null)\n        {\n            name = VersionName(name);\n        }\n\n        var contentTypeDefinition = new ContentTypeDefinition(name, displayName);\n\n        await _contentDefinitionManager.StoreTypeDefinitionAsync(contentTypeDefinition);\n\n        // Ensure it has its own part.\n        await _contentDefinitionManager.AlterTypeDefinitionAsync(name, builder => builder.WithPart(name));\n        await _contentDefinitionManager.AlterTypeDefinitionAsync(name, cfg =>\n        {\n            cfg.Creatable()\n                .Draftable()","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore.Modules/OrchardCore.ContentTypes/Services/ContentDefinitionService.cs#L50-L86","documentation":"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.","triggerScenarios":"Calling IContentDefinitionService.AddTypeAsync(name, ...) with a name that does not survive ToSafeName(), e.g. \"My Type!\", \"1Widget\", \"Type-Ünï\", or containing '/' or '.'.","commonSituations":"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.","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."],"exampleFix":"// before\nawait contentDefinitionService.AddTypeAsync(\"Product Category\", template => { });\n// after\nawait contentDefinitionService.AddTypeAsync(\"Product Category\".ToSafeName(), template => { }); // \"ProductCategory\"","handlingStrategy":"validation","validationCode":"// C#\nstatic bool IsValidContentTypeName(string name) =>\n    !string.IsNullOrEmpty(name)\n    && char.IsAsciiLetter(name[0])\n    && string.Equals(name, name.ToSafeName(), StringComparison.OrdinalIgnoreCase);\n// call AddTypeAsync only if IsValidContentTypeName(name)","typeGuard":"static bool IsSafeName(string name) =>\n    !string.IsNullOrWhiteSpace(name) && name == name.ToSafeName();","tryCatchPattern":"try\n{\n    await contentDefinitionService.AddTypeAsync(name, configure);\n}\ncatch (ArgumentException ex)\n{\n    logger.LogWarning(ex, \"Invalid content type name: {Name}\", name);\n}","preventionTips":["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."],"tags":["contenttypes","argument-validation","naming"],"backgroundTag":"invalid-identifier-format","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}