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

  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.