{"record":{"id":"d35b8fc57b13b86a","repo":"apache/maven","slug":"no-unique-source-for-s-s-s-and-s","errorCode":null,"errorMessage":"No unique Source for %s:%s: %s and %s","messagePattern":"No unique Source for (.+?):(.+?): (.+?) and (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java","lineNumber":458,"sourceCode":"        /**\n         * Returns false if the edge was added, true if it caused a cycle.\n         */\n        private boolean addEdge(Path from, Path p) {\n            try {\n                dag.addEdge(from.toString(), p.toString());\n                return false;\n            } catch (Graph.CycleDetectedException e) {\n                add(Severity.FATAL, Version.BASE, \"Cycle detected between models at \" + from + \" and \" + p, null, e);\n                return true;\n            }\n        }\n\n        public ModelSource getSource(String groupId, String artifactId) {\n            Set<ModelSource> sources = mappedSources.get(new GAKey(groupId, artifactId));\n            if (sources != null) {\n                return sources.stream()\n                        .reduce((a, b) -> {\n                            throw new IllegalStateException(String.format(\n                                    \"No unique Source for %s:%s: %s and %s\",\n                                    groupId, artifactId, a.getLocation(), b.getLocation()));\n                        })\n                        .orElse(null);\n            }\n            return null;\n        }\n\n        public void putSource(String groupId, String artifactId, ModelSource source) {\n            mappedSources\n                    .computeIfAbsent(new GAKey(groupId, artifactId), k -> new HashSet<>())\n                    .add(source);\n            // Also  register the source under the null groupId\n            if (groupId != null) {\n                putSource(null, artifactId, source);\n            }\n        }\n","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java#L440-L476","documentation":"During a recursive (reactor) build, DefaultModelBuilder caches every ModelSource it has seen keyed by groupId:artifactId (mappedSources). getSource(groupId, artifactId) folds the set for one key with a reduce whose combiner throws IllegalStateException as soon as two distinct sources are present, so the message names both conflicting locations.","triggerScenarios":"Two modules in the same reactor declare the same groupId:artifactId (regardless of version or path), or the same physical pom is reached through two different paths, so putSource registers a second source under the same GA key.","commonSituations":"Copy-pasted module poms with the same artifactId; a flat multi-module layout where an aggregator and a child collide; merging two projects that both define com.acme:common; duplicate <module> entries pointing at the same pom via different paths/symlinks.","solutions":["Open the two file locations named in the message and confirm the duplicate groupId:artifactId","Rename one module so groupId:artifactId is unique across the reactor","Remove the duplicate <module> entry (or the symlinked duplicate path) from the aggregator pom","Re-run mvn validate to confirm only one source remains for that GA"],"exampleFix":"<!-- before: two modules both declare -->\n<artifactId>common</artifactId>\n\n<!-- after: rename one module -->\n<artifactId>common-api</artifactId>","handlingStrategy":"validation","validationCode":"// Scan the reactor for duplicate groupId:artifactId before building\nMap<String, Path> seen = new HashMap<>();\nfor (Path pom : allReactorPoms) {\n    var coords = readGa(pom); // parse <groupId> and <artifactId>\n    Path prev = seen.putIfAbsent(coords, pom);\n    if (prev != null) {\n        throw new IllegalStateException(\"Duplicate module \" + coords + \": \" + prev + \" and \" + pom);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    ModelSource src = graph.getSource(groupId, artifactId);\n} catch (IllegalStateException e) {\n    // message lists both conflicting pom locations; fail the reactor build with both paths\n}","preventionTips":["Add a CI check (or enforcer-style rule) that groupId:artifactId is unique across all modules","Avoid symlinking the same module under two <module> entries","When templating new modules, always change artifactId as part of the copy step"],"tags":["maven","reactor","multi-module","duplicate-coordinates"],"backgroundTag":"duplicate-artifact-coordinates","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}