{"record":{"id":"4e95908d9556e2e6","repo":"egametang/ET","slug":"detected-cyclic-dependency","errorCode":null,"errorMessage":"Detected cyclic dependency!","messagePattern":"Detected cyclic dependency!","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.hybridclr/Scripts/Editor/Share/Meta/AssemblySorter.cs","lineNumber":46,"sourceCode":"                List<Node> sorted = new List<Node>();\n                HashSet<Node> visited = new HashSet<Node>();\n                HashSet<Node> tempMarks = new HashSet<Node>();\n\n                foreach (var node in nodes)\n                {\n                    if (!visited.Contains(node))\n                    {\n                        Visit(node, visited, tempMarks, sorted);\n                    }\n                }\n                return sorted;\n            }\n\n            private static void Visit(Node node, HashSet<Node> visited, HashSet<Node> tempMarks, List<Node> sorted)\n            {\n                if (tempMarks.Contains(node))\n                {\n                    throw new Exception(\"Detected cyclic dependency!\");\n                }\n\n                if (!visited.Contains(node))\n                {\n                    tempMarks.Add(node);\n                    foreach (var dependency in node.Dependencies)\n                    {\n                        Visit(dependency, visited, tempMarks, sorted);\n                    }\n                    tempMarks.Remove(node);\n                    visited.Add(node);\n                    sorted.Add(node);\n                }\n            }\n        }\n\n        private static List<string> SortAssemblyByReferenceOrder(IEnumerable<string> assemblies, Dictionary<string, HashSet<string>> refs)\n        {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.hybridclr/Scripts/Editor/Share/Meta/AssemblySorter.cs#L28-L64","documentation":"Thrown by AssemblySorter.TopologicalSorter.Visit when a node is re-encountered while it is still in the tempMarks set (i.e. on the current DFS path). This is the textbook cycle-detection check in a topological sort and indicates two or more assemblies reference each other in a circular dependency chain.","triggerScenarios":"SortAssemblyByReferenceOrder builds a dependency graph from each assembly's GetAssemblyRefs, then topologically sorts. If assembly A references B and B references A (directly or transitively), Visit recurses back to A while A is temp-marked and throws.","commonSituations":"Two .asmdef files with mutual AssemblyDefinitionReference entries; a circular project reference introduced by refactoring; hot update and AOT assemblies that inadvertently reference each other; Unity's own assembly graph has a cycle that normally does not surface but breaks HybridCLR's sort.","solutions":["Identify the cycle: the exception stack trace shows the Visit chain -- inspect the assembly names involved.","Break the circular reference by moving shared code into a third assembly that both depend on, or by removing one direction of the reference.","Check all .asmdef files for mutual AssemblyDefinitionReference entries and eliminate bidirectional edges.","If the cycle is intentional (e.g. generated code), restructure so the generator produces a DAG."],"exampleFix":"// before: A.asmdef references B, B.asmdef references A (cycle)\n// after: create Shared.asmdef; A and B both reference Shared; remove A<->B edge","handlingStrategy":"validation","validationCode":"// Before sorting, detect cycles in the assembly reference graph\nvar graph = BuildReferenceGraph(assemblies); // returns Dictionary<string, HashSet<string>>\nif (HasCycle(graph))\n    Debug.LogError(\"Circular assembly dependency detected.\");","typeGuard":"// Type guard for a DAG: returns true if the reference graph is acyclic\nstatic bool IsAcyclic(Dictionary<string, HashSet<string>> graph)\n{\n    var visited = new HashSet<string>();\n    var stack = new HashSet<string>();\n    bool Dfs(string node)\n    {\n        if (stack.Contains(node)) return false;\n        if (!visited.Add(node)) return true;\n        stack.Add(node);\n        foreach (var dep in graph.GetValueOrDefault(node, new HashSet<string>()))\n            if (!Dfs(dep)) return false;\n        stack.Remove(node);\n        return true;\n    }\n    return graph.Keys.All(Dfs);\n}","tryCatchPattern":null,"preventionTips":["Never create mutual .asmdef references; move shared code to a common dependency.","Add a CI check that validates the assembly graph is a DAG before building.","Review .asmdef AssemblyDefinitionReference arrays during code review for bidirectional edges."],"tags":["hybridclr","assembly-sorter","circular-dependency","topological-sort"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}