OrchardCMS/OrchardCore · error · InvalidOperationException
Circular dependency of type
Error message
Circular dependency of type '{settings.Type}' detected between '{settings.Name}' and '{resource.Name}' What it means
ResourceDictionary.AddExpandingResource detects cycles while expanding resource dependency graphs in ResourceManagement. When a resource being expanded is encountered again (i.e., it depends, directly or transitively, on itself), an InvalidOperationException is thrown naming the two resources involved. This prevents infinite recursion when building the require/expansion lists.
Solutions
- Read the exception to identify the two resources forming the cycle ('settings.Name' and 'resource.Name').
- Fix the ResourceManifest declarations so Dependencies form a DAG — remove one direction of the mutual Requires, or extract shared code into a third resource both depend on.
- Check for a self-dependency (a resource depending on its own name, often a copy-paste typo).
- After fixing, clear cached resource state and reload the page to confirm the graph resolves.
Example fix
// before (circular)
manifest.DefineScript("A").SetDependencies("B");
manifest.DefineScript("B").SetDependencies("A");
// after (acyclic: shared base)
manifest.DefineScript("Shared").SetUrl("/js/shared.js");
manifest.DefineScript("A").SetDependencies("Shared");
manifest.DefineScript("B").SetDependencies("Shared"); Defensive patterns
Strategy: validation
Validate before calling
// Validate the manifest dependency graph is acyclic before requesting resources:
bool HasCycle(Dictionary<string, string[]> deps) =>
deps.Keys.Any(n => Visit(n, deps, new HashSet<string>(), new HashSet<string>()));
bool Visit(string n, Dictionary<string, string[]> deps, HashSet<string> visiting, HashSet<string> done)
{
if (visiting.Contains(n)) return true;
if (done.Contains(n) || !deps.TryGetValue(n, out var d)) return false;
visiting.Add(n);
var cycle = d.Any(x => Visit(x, deps, visiting, done));
visiting.Remove(n); done.Add(n);
return cycle;
} Try / catch
try
{
await resourceManager.RegisterResourcesAsync();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Circular dependency"))
{
logger.LogError(ex, "Resource manifest declares a dependency cycle");
} Prevention
- Keep resource Dependencies acyclic; extract shared assets into a base resource.
- Watch for self-dependency typos where a resource name appears in its own Dependencies.
- Review ResourceManifest declarations after any refactor that moves Requires between resources.
- Test pages that require the affected resources after manifest changes.
When it happens
Trigger: Registering resource definitions (manifest) whose Dependencies form a cycle — e.g., resource A requires B and B requires A — then a page RequireSettings call expands dependencies via ExpandDependenciesImplementation and hits AddExpandingResource with a resource already on the expansion stack.
Common situations: A custom module's ResourceManifest declares A depends on B and B depends on A (often after a refactor); two scripts/styles mutually requiring each other for shared utilities; typo in a dependency name accidentally pointing at the resource itself.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Could not find a resource of type
- A feature is missing a mandatory 'Id' property in the Module
- File path must be a non-empty string.
- Top level JSON element must be an object. Instead
- Can't use the numeric key
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/dca850cda2ffdaba.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore/OrchardCore.ResourceManagement/ResourceDictionary.cs:18
using System.Collections.Specialized;
namespace OrchardCore.ResourceManagement;
#pragma warning disable CA1010 // Type 'ResourceDictionary' directly or indirectly inherits 'ICollection' without implementing any of 'ICollection<T>', 'IReadOnlyCollection<T>'. Publicly-visible types should implement the generic version to broaden usability.
public class ResourceDictionary : OrderedDictionary
#pragma warning restore CA1010
{
private readonly Stack<ResourceDefinition> _expanding = new();
public int FirstCount { get; private set; }
public int LastCount { get; private set; }
public void AddExpandingResource(ResourceDefinition resource, RequireSettings settings)
{
if (_expanding.Contains(resource))
{
throw new InvalidOperationException($"Circular dependency of type '{settings.Type}' detected between '{settings.Name}' and '{resource.Name}'");
}
_expanding.Push(resource);
}
public void AddExpandedResource(ResourceDefinition resource, RequireSettings settings)
{
_expanding.Pop();
if (settings.Position != ResourcePosition.ByDependency)
{
var existing = (RequireSettings)this[resource];
if (existing == null || existing.Position == ResourcePosition.ByDependency)
{
if (settings.Position == ResourcePosition.First)
{
FirstCount++;
}View on GitHub (pinned to 4306c0717f)