apache/maven · warning
artifact '{}' already attached, replacing previous instance
Error message
artifact '{}' already attached, replacing previous instance What it means
MavenProject.addAttachedArtifact() was called with coordinates (groupId:artifactId:version:classifier:type) that already exist in the attached-artifacts list. Since 3.0.x the method replaces the previous instance instead of throwing DuplicateArtifactAttachmentException (kept only for binary compatibility); the old file reference is discarded. The method is deprecated in favor of MavenProjectHelper. The warning fires on every replacement, which is how plugins like shade intentionally retarget an attached artifact's file path.
Source
Thrown at impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java:1095
return this.injectedProfileIds;
}
/**
* Add or replace an artifact. This method is now deprecated. Use the @{MavenProjectHelper} to attach artifacts to a
* project. In spite of the 'throws' declaration on this API, this method has never thrown an exception since Maven
* 3.0.x. Historically, it logged and ignored a second addition of the same g/a/v/c/t. Now it replaces the file for
* the artifact, so that plugins (e.g. shade) can change the pathname of the file for a particular set of
* coordinates.
*
* @param artifact the artifact to add or replace.
* @deprecated Please use {@link MavenProjectHelper}
* @throws DuplicateArtifactAttachmentException will never happen but leave it for backward compatibility
*/
public void addAttachedArtifact(Artifact artifact) throws DuplicateArtifactAttachmentException {
// if already there we remove it and add again
int index = attachedArtifacts.indexOf(artifact);
if (index >= 0) {
LOGGER.warn("artifact '{}' already attached, replacing previous instance", artifact);
attachedArtifacts.set(index, artifact);
} else {
attachedArtifacts.add(artifact);
}
}
/**
* Returns a read-only list of the attached artifacts to this project.
*
* @return the attached artifacts of this project
*/
public List<Artifact> getAttachedArtifacts() {
if (attachedArtifacts == null) {
attachedArtifacts = new ArrayList<>();
}
return Collections.unmodifiableList(attachedArtifacts);
}
View on GitHub (pinned to e4093d4e12)
Solutions
- Inspect the effective lifecycle (mvn -X or mvn help:effective-pom) for two executions binding plugins that attach artifacts with the same classifier
- Give each attachment a distinct <classifier> so both files are kept
- If the replacement is intended (shade retargeting), treat the warning as expected noise or raise the logger threshold for org.apache.maven.project.MavenProject
- In custom mojos, switch to MavenProjectHelper.attachArtifact(...) and guard with a getAttachedArtifacts() lookup before attaching
Example fix
<!-- before: two executions attach artifacts with no classifier, second replaces first -->
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
</execution>
</executions>
</plugin>
<!-- after: shaded jar gets its own classifier, both artifacts installed -->
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>shaded</shadedClassifierName>
</configuration>
</execution>
</executions>
</plugin> Defensive patterns
Strategy: validation
Validate before calling
// In a mojo: only attach when the coordinates are not already present
import org.apache.maven.artifact.Artifact;
boolean alreadyAttached(MavenProject project, Artifact artifact) {
return project.getAttachedArtifacts().stream().anyMatch(a ->
a.getArtifactId().equals(artifact.getArtifactId())
&& a.getGroupId().equals(artifact.getGroupId())
&& a.getVersion().equals(artifact.getVersion())
&& java.util.Objects.equals(a.getClassifier(), artifact.getClassifier())
&& a.getType().equals(artifact.getType()));
}
if (!alreadyAttached(project, artifact)) {
project.addAttachedArtifact(artifact); // prefer MavenProjectHelper in production code
} Prevention
- Prefer MavenProjectHelper.attachArtifact(...) over the deprecated MavenProject.addAttachedArtifact
- Give every attached artifact a unique classifier per producing execution
- Review effective lifecycle bindings so two executions never attach the same g/a/v/c/t
- Remember DuplicateArtifactAttachmentException is never thrown anymore; do not rely on it for control flow
When it happens
Trigger: A mojo calls project.addAttachedArtifact(artifact) or MavenProjectHelper.attachArtifact(...) twice with identical g/a/v/c/t but different files: two plugin executions in the same lifecycle run both attaching (e.g. shade + source plugin attaching the same classifier), or a plugin re-running on a cached MavenProject instance.
Common situations: shade plugin replacing the main artifact's file after another plugin already attached it; source/javadoc plugins executing twice due to duplicated execution bindings; custom mojos attaching test-jar and a classified jar with an empty classifier by mistake; incremental builds reusing a project instance.
Related errors
- For artifact {}: An attached artifact must have a different
- Cannot attach artifact to project: groupId, artifactId and v
- Cannot change the artifactId for an attached artifact. It is
- Cannot change the version information for an attached artifa
- Cannot change the download information for an attached artif
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/29438537ad6ac554.
Report an issue: GitHub.