apache/maven · error · IllegalStateException
No unique Source for %s:%s: %s and %s
Error message
No unique Source for %s:%s: %s and %s
What it means
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.
Source
Thrown at impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java:458
/**
* Returns false if the edge was added, true if it caused a cycle.
*/
private boolean addEdge(Path from, Path p) {
try {
dag.addEdge(from.toString(), p.toString());
return false;
} catch (Graph.CycleDetectedException e) {
add(Severity.FATAL, Version.BASE, "Cycle detected between models at " + from + " and " + p, null, e);
return true;
}
}
public ModelSource getSource(String groupId, String artifactId) {
Set<ModelSource> sources = mappedSources.get(new GAKey(groupId, artifactId));
if (sources != null) {
return sources.stream()
.reduce((a, b) -> {
throw new IllegalStateException(String.format(
"No unique Source for %s:%s: %s and %s",
groupId, artifactId, a.getLocation(), b.getLocation()));
})
.orElse(null);
}
return null;
}
public void putSource(String groupId, String artifactId, ModelSource source) {
mappedSources
.computeIfAbsent(new GAKey(groupId, artifactId), k -> new HashSet<>())
.add(source);
// Also register the source under the null groupId
if (groupId != null) {
putSource(null, artifactId, source);
}
}
View on GitHub (pinned to e4093d4e12)
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
Example fix
<!-- before: two modules both declare --> <artifactId>common</artifactId> <!-- after: rename one module --> <artifactId>common-api</artifactId>
Defensive patterns
Strategy: validation
Validate before calling
// Scan the reactor for duplicate groupId:artifactId before building
Map<String, Path> seen = new HashMap<>();
for (Path pom : allReactorPoms) {
var coords = readGa(pom); // parse <groupId> and <artifactId>
Path prev = seen.putIfAbsent(coords, pom);
if (prev != null) {
throw new IllegalStateException("Duplicate module " + coords + ": " + prev + " and " + pom);
}
} Try / catch
try {
ModelSource src = graph.getSource(groupId, artifactId);
} catch (IllegalStateException e) {
// message lists both conflicting pom locations; fail the reactor build with both paths
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Two or more projects in the reactor have the same identifier
- Edge between '{}' and '{}' introduces to cycle in the graph
- Project '{}' is duplicated in the reactor
- Try running the build up to the lifecycle phase "package"
- Unable to find the root directory. Create a .mvn directory i
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/d35b8fc57b13b86a.
Report an issue: GitHub.