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
- Read the cycle path in the exception message: it names the modules forming the loop, e.g. [A -> B -> A]
- Break the cycle by removing or reversing one dependency edge — typically by extracting the shared code into a third module both depend on
- 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
- 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
- Keep inter-module dependencies one-directional: lower layers depend on higher, never back
- Extract shared code into a common module instead of adding back-references
- Run 'mvn validate' after every dependency change in a multi-module reactor
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
- Two or more projects in the reactor have the same identifier
- Project '{}' is duplicated in the reactor
- No unique Source for %s:%s: %s and %s
- Edge between '${from}' and '${to}' introduces to cycle in th
- Try running the build up to the lifecycle phase "package"
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/d04d5fc5e28f2279.
Report an issue: GitHub.