{"record":{"id":"373e396d63ca0caa","repo":"OrchardCMS/OrchardCore","slug":"a-feature-is-missing-a-mandatory-id-property-in-the-module","errorCode":null,"errorMessage":"A feature is missing a mandatory 'Id' property in the Module '{extensionInfo.Id}'","messagePattern":"A feature is missing a mandatory 'Id' property in the Module '(.+?)'","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore/Extensions/Features/FeaturesProvider.cs","lineNumber":29,"sourceCode":"    /// <param name=\"featureBuilderEvents\"></param>\n    public FeaturesProvider(IEnumerable<IFeatureBuilderEvents> featureBuilderEvents)\n        : base(featureBuilderEvents)\n    {\n    }\n\n    public override IEnumerable<IFeatureInfo> GetFeatures(IExtensionInfo extensionInfo, IManifestInfo manifestInfo)\n    {\n        var featuresInfos = new List<IFeatureInfo>();\n\n        // Features and Dependencies live within this section\n        var features = manifestInfo.ModuleInfo.Features;\n        if (features.Count > 0)\n        {\n            foreach (var feature in features)\n            {\n                if (string.IsNullOrWhiteSpace(feature.Id))\n                {\n                    throw new ArgumentException(\n                        $\"A {nameof(feature)} is missing a mandatory '{nameof(feature.Id)}' property in the Module '{extensionInfo.Id}'\");\n                }\n\n                // Attribute properties are transparently resolved by the instances themselves for convenience\n                var featureId = feature.Id;\n                var featureName = feature.Name;\n\n                var featureDependencyIds = feature.Dependencies;\n                var featureBeforeDependencyIds = feature.Before;\n                var featureAfterDependencyIds = feature.After;\n\n                // Categorize, Prioritize, Describe, using the ModuleInfo (ModuleAttribute) as the back stop\n                var featureCategory = feature.Categorize(manifestInfo.ModuleInfo);\n                var featurePriority = feature.Prioritize(manifestInfo.ModuleInfo);\n                var featureDescription = feature.Describe(manifestInfo.ModuleInfo);\n                var featureDefaultTenantOnly = feature.DefaultTenantOnly;\n                var featureIsAlwaysEnabled = feature.IsAlwaysEnabled;\n                var featureEnabledByDependencyOnly = feature.EnabledByDependencyOnly;","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore/Extensions/Features/FeaturesProvider.cs#L11-L47","documentation":"FeaturesProvider builds the feature list for each module extension during module discovery. Every feature exposed by a module must carry a non-empty Id, since feature ids are the primary key for activation, dependency resolution, and DI mapping. If an extension declares a feature whose Id is null, empty, or whitespace, discovery is aborted with this ArgumentException.","triggerScenarios":"Calling GetFeatures(extensionInfo) where the extension's feature list (typically constructed from [Feature] attributes or an IFeatureProvider) contains an entry whose Id property is null, empty, or whitespace.","commonSituations":"A custom module declares [Feature(Name = \"My Feature\")] without setting Id; a hand-written IFeatureAttributeConfiguration misconfigures attribute property binding; a refactor renames or removes the Id property from a feature attribute.","solutions":["Set the Id property on every [Feature] attribute or feature descriptor in the offending module (the module name is in the exception message).","Ensure feature Ids are non-empty strings, conventionally 'ModuleName.FeatureName' for secondary features.","Rebuild the module so updated attribute metadata is loaded, then restart the application."],"exampleFix":"// before\n[Feature(Name = \"Sample Feature\")]\npublic class Startup : StartupBase { }\n\n// after\n[Feature(Id = \"My.SampleModule\", Name = \"Sample Feature\")]\npublic class Startup : StartupBase { }","handlingStrategy":"validation","validationCode":"var features = extensionInfo.Features ?? [];\nif (features.Any(f => string.IsNullOrWhiteSpace(f.Id)))\n    throw new InvalidOperationException($\"Module '{extensionInfo.Id}' has a feature without an Id.\");","typeGuard":"bool HasValidId(IFeature feature) => !string.IsNullOrWhiteSpace(feature.Id);","tryCatchPattern":"try { provider.GetFeatures(extensionInfo); }\ncatch (ArgumentException ex) { _logger.LogError(ex, \"Module {Module} has a feature missing its Id\", extensionInfo.Id); }","preventionTips":["Always set Id on [Feature] attributes; use ModuleName.FeatureName convention for secondary features.","Add a unit test asserting every module's features have non-empty Ids.","Never rename/remove the Id property of feature attributes without grepping all modules."],"tags":["modules","features","configuration","startup"],"backgroundTag":"missing-required-argument","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"}