{"record":{"id":"9c4d6c822bd3bd4b","repo":"apache/maven","slug":"a-dependency-has-introduced-a-cycle","errorCode":null,"errorMessage":"A dependency has introduced a cycle","messagePattern":"A dependency has introduced a cycle","errorType":"exception","errorClass":"CyclicDependencyException","httpStatus":null,"severity":"error","filePath":"compat/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java","lineNumber":91,"sourceCode":"    public Artifact getArtifact() {\n        return artifact;\n    }\n\n    public Object getKey() {\n        return artifact.getDependencyConflictId();\n    }\n\n    public void addDependencies(\n            Set<Artifact> artifacts, List<ArtifactRepository> remoteRepositories, ArtifactFilter filter)\n            throws CyclicDependencyException, OverConstrainedVersionException {\n        if (artifacts != null && !artifacts.isEmpty()) {\n            children = new ArrayList<>(artifacts.size());\n\n            for (Artifact a : artifacts) {\n                if (parents.contains(a.getDependencyConflictId())) {\n                    a.setDependencyTrail(getDependencyTrail());\n\n                    throw new CyclicDependencyException(\"A dependency has introduced a cycle\", a);\n                }\n\n                children.add(new ResolutionNode(a, remoteRepositories, this));\n            }\n            children = Collections.unmodifiableList(children);\n        } else {\n            children = Collections.emptyList();\n        }\n        trail = null;\n    }\n\n    /**\n     * @return {@link List} &lt; {@link String} &gt; with artifact ids\n     * @throws OverConstrainedVersionException if version specification is over constrained\n     */\n    public List<String> getDependencyTrail() throws OverConstrainedVersionException {\n        List<Artifact> trial = getTrail();\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/compat/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java#L73-L109","documentation":"ResolutionNode.addDependencies() builds the legacy dependency graph; when a candidate dependency's conflict id is already among the current node's parents, adding it would make the artifact its own ancestor, so Maven throws CyclicDependencyException. The offending artifact is attached to the exception and its dependency trail is set beforehand, so the trail plus message identify the exact closing edge of the cycle.","triggerScenarios":"Resolving a dependency graph (through the legacy resolver in maven-compat, e.g. old plugins or DefaultArtifactCollector) where project A depends on B and B, transitively, depends back on A.","commonSituations":"Sibling modules referencing each other (api depends on impl while impl depends on api); test-jar dependencies creating module cycles; third-party libraries accidentally published with cyclic POMs.","solutions":["Run mvn dependency:tree -Dverbose (or dependency:analyze) to locate the cycle using the artifact reported by the exception","Break the cycle in your modules: remove one edge, or refactor shared code into a module both depend on","If the cycle arrives via a published third-party POM, exclude the transitive dependency that closes the cycle","Re-run the build to confirm the graph is acyclic"],"exampleFix":"<!-- before: module 'impl' pulls 'api' transitively, closing a cycle -->\n<dependency>\n  <groupId>com.example</groupId>\n  <artifactId>shared-lib</artifactId>\n</dependency>\n<!-- after: exclude the edge that closes the cycle -->\n<dependency>\n  <groupId>com.example</groupId>\n  <artifactId>shared-lib</artifactId>\n  <exclusions>\n    <exclusion>\n      <groupId>com.example</groupId>\n      <artifactId>api</artifactId>\n    </exclusion>\n  </exclusions>\n</dependency>","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"Catch CyclicDependencyException; read getArtifact() and its dependency trail to identify the closing edge, then fail the build with the cycle path printed - do not retry, the graph is structurally invalid.","preventionTips":["Keep module dependency directions one-way (impl -> api, never both); enforce in reviews.","Run mvn dependency:tree -Dverbose in CI to surface cycles before they hit the resolver.","Be cautious with test-jar type dependencies; they are a common source of module cycles."],"tags":["maven","dependency","cycle","graph","resolution"],"backgroundTag":"cyclic-dependency-detected","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}