{"record":{"id":"dca850cda2ffdaba","repo":"OrchardCMS/OrchardCore","slug":"circular-dependency-of-type-settings-type-detected-between","errorCode":null,"errorMessage":"Circular dependency of type '{settings.Type}' detected between '{settings.Name}' and '{resource.Name}'","messagePattern":"Circular dependency of type '(.+?)' detected between '(.+?)' and '(.+?)'","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.ResourceManagement/ResourceDictionary.cs","lineNumber":18,"sourceCode":"using System.Collections.Specialized;\n\nnamespace OrchardCore.ResourceManagement;\n\n#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.\npublic class ResourceDictionary : OrderedDictionary\n#pragma warning restore CA1010\n{\n    private readonly Stack<ResourceDefinition> _expanding = new();\n\n    public int FirstCount { get; private set; }\n    public int LastCount { get; private set; }\n\n    public void AddExpandingResource(ResourceDefinition resource, RequireSettings settings)\n    {\n        if (_expanding.Contains(resource))\n        {\n            throw new InvalidOperationException($\"Circular dependency of type '{settings.Type}' detected between '{settings.Name}' and '{resource.Name}'\");\n        }\n\n        _expanding.Push(resource);\n    }\n\n    public void AddExpandedResource(ResourceDefinition resource, RequireSettings settings)\n    {\n        _expanding.Pop();\n\n        if (settings.Position != ResourcePosition.ByDependency)\n        {\n            var existing = (RequireSettings)this[resource];\n            if (existing == null || existing.Position == ResourcePosition.ByDependency)\n            {\n                if (settings.Position == ResourcePosition.First)\n                {\n                    FirstCount++;\n                }","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.ResourceManagement/ResourceDictionary.cs#L1-L36","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (circular)\nmanifest.DefineScript(\"A\").SetDependencies(\"B\");\nmanifest.DefineScript(\"B\").SetDependencies(\"A\");\n\n// after (acyclic: shared base)\nmanifest.DefineScript(\"Shared\").SetUrl(\"/js/shared.js\");\nmanifest.DefineScript(\"A\").SetDependencies(\"Shared\");\nmanifest.DefineScript(\"B\").SetDependencies(\"Shared\");","handlingStrategy":"validation","validationCode":"// Validate the manifest dependency graph is acyclic before requesting resources:\nbool HasCycle(Dictionary<string, string[]> deps) =>\n    deps.Keys.Any(n => Visit(n, deps, new HashSet<string>(), new HashSet<string>()));\n\nbool Visit(string n, Dictionary<string, string[]> deps, HashSet<string> visiting, HashSet<string> done)\n{\n    if (visiting.Contains(n)) return true;\n    if (done.Contains(n) || !deps.TryGetValue(n, out var d)) return false;\n    visiting.Add(n);\n    var cycle = d.Any(x => Visit(x, deps, visiting, done));\n    visiting.Remove(n); done.Add(n);\n    return cycle;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    await resourceManager.RegisterResourcesAsync();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Circular dependency\"))\n{\n    logger.LogError(ex, \"Resource manifest declares a dependency cycle\");\n}","preventionTips":["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."],"tags":["resources","dependency-cycle","configuration","resourcemanagement"],"backgroundTag":"invalid-state-transition","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"}