abpframework/abp · error · ArgumentException

Cyclic dependency found! Item: {item}

Error message

Cyclic dependency found! Item: {item}

What it means

Thrown by DefaultBuildProjectListSorter during a topological sort of .NET projects. The visited-map DFS detects that a project is still 'in process' (on the current recursion stack) when reached again, which is the textbook signature of a reference cycle. Build ordering cannot be produced until the cycle is broken.

Source

Thrown at framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DefaultBuildProjectListSorter.cs:42

        }

        return sorted;
    }

    private void SortByDependenciesVisit(
        List<DotNetProjectInfo> source,
        DotNetProjectInfo item,
        List<DotNetProjectInfo> sorted,
        Dictionary<DotNetProjectInfo, bool> visited)
    {
        bool inProcess;
        var alreadyVisited = visited.TryGetValue(item, out inProcess);

        if (alreadyVisited)
        {
            if (inProcess)
            {
                throw new ArgumentException("Cyclic dependency found! Item: " + item);
            }
        }
        else
        {
            visited[item] = true;

            var dependencies = item.Dependencies;
            if (dependencies != null)
            {
                foreach (var dependency in dependencies)
                {
                    var dependencyItem = source.FirstOrDefault(e => e.CsProjPath == dependency.CsProjPath);
                    if (dependencyItem != null)
                    {
                        SortByDependenciesVisit(source, dependencyItem, sorted, visited);
                    }
                }
            }

View on GitHub (pinned to 7ed43b1931)

Solutions

  1. Identify the cycle: the thrown item string and its Dependencies point to the loop; trace ProjectReference chains from the named .csproj back to itself.
  2. Break the cycle by removing the offending ProjectReference (use a shared interface/abstraction project instead of a back-reference).
  3. Run 'dotnet build' on the affected projects to confirm the cycle is also flagged by the SDK.
  4. Use a dependency-analysis tool (e.g., 'dotnet list package' or a project-reference graph viewer) to visualize and remove the loop.

Example fix

<!-- before: ProjectA.csproj references ProjectB, ProjectB references ProjectA -->
<ProjectReference Include="..\ProjectB\ProjectB.csproj" />

<!-- after: extract shared code into a ProjectShared that both reference, with no back-edge -->
<!-- ProjectA -> ProjectShared, ProjectB -> ProjectShared -->
Defensive patterns

Strategy: validation

Validate before calling

// Detect a project-reference cycle before invoking the sorter.
bool HasCycle(List<DotNetProjectInfo> projects)
{
    var byPath = projects.ToDictionary(p => p.CsProjPath);
    var visited = new HashSet<string>();
    var stack = new HashSet<string>();
    bool Dfs(string path)
    {
        if (stack.Contains(path)) return true;
        if (!visited.Add(path)) return false;
        stack.Add(path);
        if (byPath.TryGetValue(path, out var p) && p.Dependencies != null)
            foreach (var d in p.Dependencies)
                if (byPath.ContainsKey(d.CsProjPath) && Dfs(d.CsProjPath)) return true;
        stack.Remove(path);
        return false;
    }
    return projects.Any(p => Dfs(p.CsProjPath));
}
if (HasCycle(projects)) throw new InvalidOperationException("Project reference cycle detected; remove the back-reference.");

Type guard

// (uses validation code above; no type to guard)

Try / catch

try
{
    var ordered = sorter.SortByDependencies(projects);
}
catch (ArgumentException ex) when (ex.Message.Contains("Cyclic dependency", StringComparison.Ordinal))
{
    logger.LogError(ex, "Cycle detected while ordering projects; remove the offending ProjectReference.");
    throw;
}

Prevention

When it happens

Trigger: SortByDependenciesVisit re-enters a DotNetProjectInfo whose visited flag is still true (in-process). This means project A depends on B and B (transitively) depends on A, via CsProjPath matching in item.Dependencies.

Common situations: Two projects reference each other (ProjectReference cycle); a newly added reference closes a cycle across three or more projects; merged solutions that previously had isolated cycles; refactoring that introduced a back-reference; shared/abstractions projects that accidentally reference a downstream project.

Related errors


AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13). Data as JSON: /api/errors/420365323b8968c5. Report an issue: GitHub.