abpframework/abp · error · ArgumentException

Cyclic dependency found! Item: {item}

Error message

Cyclic dependency found! Item: {item}

What it means

Thrown by AbpListExtensions.SortByDependenciesVisit during topological sorting when an item is revisited while still marked in-process (visited[item] == true). That re-entrancy means the dependency graph has a cycle: A (transitively) depends on A, so no valid linear ordering exists. The exception names the offending item.

Source

Thrown at framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs:234

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T">The type of the members of values.</typeparam>
    /// <param name="item">Item to resolve</param>
    /// <param name="getDependencies">Function to resolve the dependencies</param>
    /// <param name="sorted">List with the sortet items</param>
    /// <param name="visited">Dictionary with the visited items</param>
    private static void SortByDependenciesVisit<T>(T item, Func<T, IEnumerable<T>> getDependencies, List<T> sorted,
        Dictionary<T, bool> visited) where T : notnull
    {
        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 = getDependencies(item);
            if (dependencies != null)
            {
                foreach (var dependency in dependencies)
                {
                    SortByDependenciesVisit(dependency, getDependencies, sorted, visited);
                }
            }

            visited[item] = false;
            sorted.Add(item);
        }

View on GitHub (pinned to 7ed43b1931)

Solutions

  1. Break the cycle: remove one direction of the [DependsOn] attribute or restructure so dependencies are acyclic.
  2. Inspect the exception's item name to locate the cycle, then trace its dependencies to find the back-edge.
  3. If the cycle is intentional, refactor to remove the dependency (e.g. via events or lazy resolution) since topological order requires a DAG.
  4. Add a unit test asserting the dependency graph is acyclic before sorting.

Example fix

// before — circular module dependency
[DependsOn(typeof(BModule))]
public class AModule : AbpModule { }
[DependsOn(typeof(AModule))] // cycle: A -> B -> A
public class BModule : AbpModule { }

// after — break the cycle
[DependsOn(typeof(BModule))]
public class AModule : AbpModule { }
public class BModule : AbpModule { } // remove the reverse DependsOn
Defensive patterns

Strategy: validation

Validate before calling

// Detect a cycle before topological sort using a DFS with recursion-stack coloring
static bool HasCycle<T>(IEnumerable<T> nodes, Func<T, IEnumerable<T>> deps, IEqualityComparer<T>? cmp = null) where T : notnull
{
    var state = new Dictionary<T, byte>(cmp ?? EqualityComparer<T>.Default); // 0=unseen,1=in-progress,2=done
    bool Dfs(T n) {
        if (state.TryGetValue(n, out var s)) return s == 1;
        state[n] = 1;
        foreach (var d in deps(n) ?? Enumerable.Empty<T>()) if (Dfs(d)) return true;
        state[n] = 2; return false;
    }
    return nodes.Any(Dfs);
}

Try / catch

try { var ordered = source.SortByDependencies(getDependencies); }
catch (ArgumentException ex) when (ex.Message.StartsWith("Cyclic dependency"))
{ /* log the item, then break the [DependsOn] cycle and retry */ }

Prevention

When it happens

Trigger: Calling source.SortByDependencies(getDependencies) where getDependencies returns a graph containing a cycle — e.g. module A depends on B and B depends on A. Most commonly hit during ABP module loading when modules declare circular DependsOn relationships.

Common situations: Two ABP modules with mutual [DependsOn] attributes; a service/feature dependency cycle passed to SortByDependencies; self-dependency (an item whose getDependencies returns itself).

Related errors


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