apache/maven · error · CycleDetectedException
Edge between '${from}' and '${to}' introduces to cycle in th
Error message
Edge between '${from}' and '${to}' introduces to cycle in the graph What it means
Graph is the small graph DefaultModelBuilder uses to record model relations (parent/child, relativePath edges) during recursive builds. addEdge() inserts the edge, runs a DFS cycle check, and if the new edge closes a loop it removes the edge and throws CycleDetectedException carrying the cycle path. At the model-builder level this surfaces as the FATAL problem 'Cycle detected between models at X and Y'.
Source
Thrown at impl/maven-impl/src/main/java/org/apache/maven/impl/model/Graph.java:40
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
class Graph {
final Map<String, Set<String>> graph = new LinkedHashMap<>();
synchronized void addEdge(String from, String to) throws CycleDetectedException {
if (graph.computeIfAbsent(from, l -> new HashSet<>()).add(to)) {
List<String> cycle = visitCycle(graph, Collections.singleton(to), new HashMap<>(), new LinkedList<>());
if (cycle != null) {
// remove edge which introduced cycle
throw new CycleDetectedException(
"Edge between '" + from + "' and '" + to + "' introduces to cycle in the graph", cycle);
}
}
}
private enum DfsState {
VISITING,
VISITED
}
private static List<String> visitCycle(
Map<String, Set<String>> graph,
Collection<String> children,
Map<String, DfsState> stateMap,
LinkedList<String> cycle) {
if (children != null) {
for (String v : children) {
DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);View on GitHub (pinned to e4093d4e12)
Solutions
- Map the parent chain of the two poms named in the message and break the loop: every chain must terminate at a root pom that has no parent
- Fix or remove <relativePath> entries so each pom resolves its true parent
- Make sure the root/aggregator pom is never also the parent of a pom above it
- Run mvn -e to see the full cycle path carried by the exception
Example fix
<!-- before: child/pom.xml has parent = root, but root/pom.xml also claims child as its parent --> <!-- fix: keep the chain one-directional --> <parent> <groupId>com.acme</groupId> <artifactId>root</artifactId> <relativePath>../pom.xml</relativePath> </parent> <!-- root pom must NOT declare <parent> pointing back at child -->
Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate the inheritance graph: walk each pom's parent chain and detect repeats
static Optional<Path> findCycle(Map<Path, Path> parentOf) { // child -> resolved parent pom
for (Path start : parentOf.keySet()) {
Set<Path> seen = new HashSet<>();
for (Path p = start; p != null; p = parentOf.get(p)) {
if (!seen.add(p)) return Optional.of(p);
}
}
return Optional.empty();
} Try / catch
try {
resultGraph.addEdge(from, to);
} catch (Graph.CycleDetectedException e) {
// e.getCycle() lists the loop; report it and stop instead of retrying
} Prevention
- Enforce a single root pom with no <parent> and keep all inheritance edges pointing 'up' the tree
- Validate parent/relativePath pairs in CI (e.g. mvn validate -q or a custom checker) before deep builds
- After moving poms, grep all <relativePath> values for references that now point at children
When it happens
Trigger: Pom A declares pom B as its parent while B (or something in B's parent chain) declares A as its parent; <relativePath> values that make the inheritance graph loop back on itself.
Common situations: Hand-edited multi-module projects where parent/child relations were swapped; an aggregator accidentally declared as parent of its own parent; refactoring that moved parent poms but left stale relativePath values pointing at children.
Related errors
- Edge between '{}' and '{}' introduces to cycle in the graph
- A dependency has introduced a cycle
- Failed to process POM for " + artifact.getId() + ": " + miss
- lifecycle bindings injector is missing
- neither pomFile nor modelSource can be null
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/49e9149f56ce9549.
Report an issue: GitHub.