apache/maven · error · IllegalStateException

No unique Source for

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.

Solutions

  1. Open the two file locations named in the message and confirm the duplicate groupId:artifactId
  2. Rename one module so groupId:artifactId is unique across the reactor
  3. Remove the duplicate <module> entry (or the symlinked duplicate path) from the aggregator pom
  4. 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

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


AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21). Data as JSON: /api/errors/d35b8fc57b13b86a. Report an issue: GitHub.

Appendix: 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)