apache/maven · error · CycleDetectedException

Edge between '{}' and '{}' introduces to cycle in the graph

Error message

Edge between '{}' and '{}' introduces to cycle in the graph

What it means

CycleDetectedException is thrown by Graph.addEdge() when adding an edge (a dependency relationship) would create a directed cycle in the project graph. The edge is rolled back before throwing, and the exception carries the list of vertex labels forming the cycle. This graph is used by the reactor's project sorter (ProjectSorter), so the vertices are Maven module ids and the cycle means module A depends on module B while B (transitively) depends on A.

Source

Thrown at impl/maven-core/src/main/java/org/apache/maven/internal/impl/Graph.java:57

        return vertices.get(id);
    }

    public Collection<Vertex> getVertices() {
        return vertices.values();
    }

    Vertex addVertex(String label) {
        return vertices.computeIfAbsent(label, Vertex::new);
    }

    void addEdge(Vertex from, Vertex to) throws CycleDetectedException {
        from.children.add(to);
        to.parents.add(from);
        List<String> cycle = findCycle(to);
        if (cycle != null) {
            // remove edge which introduced cycle
            removeEdge(from, to);
            throw new CycleDetectedException(
                    "Edge between '" + from.label + "' and '" + to.label + "' introduces to cycle in the graph", cycle);
        }
    }

    void removeEdge(Vertex from, Vertex to) {
        from.children.remove(to);
        to.parents.remove(from);
    }

    List<String> visitAll() {
        return visitAll(vertices.values(), new HashMap<>(), new ArrayList<>());
    }

    List<String> findCycle(Vertex vertex) {
        return visitCycle(Collections.singleton(vertex), new HashMap<>(), new LinkedList<>());
    }

    private static List<String> visitAll(

View on GitHub (pinned to e4093d4e12)

Solutions

  1. Read the cycle path in the exception message: it names the modules forming the loop, e.g. [A -> B -> A]
  2. Break the cycle by removing or reversing one dependency edge — typically by extracting the shared code into a third module both depend on
  3. If one edge is only needed for tests, move that test to the other module or use test-jar artifacts carefully so the compile-time graph stays acyclic
  4. Re-run 'mvn validate' after each edge change to confirm the reactor sorts again

Example fix

<!-- before: a/pom.xml and b/pom.xml depend on each other -->
<dependency><groupId>org.acme</groupId><artifactId>b</artifactId></dependency> <!-- in a -->
<dependency><groupId>org.acme</groupId><artifactId>a</artifactId></dependency> <!-- in b -->

<!-- after: extract shared code into 'common' -->
<dependency><groupId>org.acme</groupId><artifactId>common</artifactId></dependency> <!-- in both a and b -->
Defensive patterns

Strategy: validation

Validate before calling

// before adding an inter-module dependency, check the reverse direction
Optional<Dependency> reverse = project.getDependencies().stream()
    .filter(d -> d.getArtifactId().equals(otherModuleArtifactId)).findFirst();
if (reverse.isPresent()) throw new IllegalStateException("Would create a module cycle");

Try / catch

try {
    ProjectSorter sorter = new ProjectSorter(projects);
} catch (CycleDetectedException e) {
    List<String> cycle = e.getCycle();
    // report the module loop and fail the pipeline with a clear message
}

Prevention

When it happens

Trigger: Building a multi-module reactor where module interdependencies form a cycle: module A declares a <dependency> on B and B declares one on A; or a longer cycle A->B->C->A created by adding one dependency between modules; also cycles introduced via plugin <extensions> ordering or parent/child module reference mistakes during reactor sorting.

Common situations: Adding an inter-module dependency without checking the existing direction; refactoring that moves a class into another module while both modules still reference each other; accidental cyclic dependency introduced by generating code into the wrong module; test-support modules that depend on the module under test.

Related errors


AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21). Data as JSON: /api/errors/d04d5fc5e28f2279. Report an issue: GitHub.