OrchardCMS/OrchardCore · error · InvalidOperationException

Could not resolve main feature for type

Error message

Could not resolve main feature for type {dependency.Name}.

What it means

GetFeatureForDependency resolves the 'main' feature for a type: among the features mapped to the dependency type, it prefers the one whose Id equals its extension's Id (the module's root feature), falling back to the first feature. If the type is not in the map at all, this InvalidOperationException is thrown.

Solutions

  1. Confirm the type is contributed by a module Startup class so TryAdd runs for it.
  2. Run the lookup only after shell/feature initialization is complete.
  3. Guard the call by checking membership first (GetFeaturesForDependency / TryGetValue) and handling unknown types explicitly.

Example fix

// before
var feature = provider.GetFeatureForDependency(typeof(UnknownService));

// after
var known = provider.GetFeaturesForDependency(typeof(UnknownService)); // register UnknownService in a module Startup, or null-check first
Defensive patterns

Strategy: type-guard

Validate before calling

// probe membership without throwing
bool known;
try { provider.GetFeaturesForDependency(typeof(T)); known = true; } catch (InvalidOperationException) { known = false; }

Type guard

bool HasMainFeature(Type dependency) =>
    provider.GetFeaturesForDependency(dependency)
        ?.Any(f => f.Id == f.Extension.Id) == true;

Try / catch

try { var feature = provider.GetFeatureForDependency(type); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Could not resolve main feature")) { feature = null; }

Prevention

When it happens

Trigger: Calling GetFeatureForDependency(type) where type was never added via TryAdd, so _features contains no entry for it.

Common situations: Querying a type registered outside module startup classes (e.g., host-level services); calling before shell composition completes; typo'd or renamed service type after a refactor.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/81c33d6436b40465. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore/OrchardCore/Extensions/Features/TypeFeatureProvider.cs:29

    {
        if (_features.TryGetValue(dependency, out var features))
        {
            return features.First().Extension;
        }

        throw new InvalidOperationException($"Could not resolve extension for type {dependency.Name}.");
    }

    public IFeatureInfo GetFeatureForDependency(Type dependency)
    {
        if (_features.TryGetValue(dependency, out var features))
        {
            // Gets the first feature that has the same ID as the extension, if any. 
            // Otherwise returns the first feature.
            return features.FirstOrDefault(feature => feature.Extension.Id == feature.Id) ?? features.First();
        }

        throw new InvalidOperationException($"Could not resolve main feature for type {dependency.Name}.");
    }

    public IEnumerable<IFeatureInfo> GetFeaturesForDependency(Type dependency)
    {
        if (_features.TryGetValue(dependency, out var features))
        {
            return features;
        }

        throw new InvalidOperationException($"Could not resolve features for type {dependency.Name}.");
    }

    public IEnumerable<Type> GetTypesForFeature(IFeatureInfo feature)
    {
        return _features.Where(kv => kv.Value.Contains(feature)).Select(kv => kv.Key);
    }

    public void TryAdd(Type type, IFeatureInfo feature)

View on GitHub (pinned to 4306c0717f)