Skip to content

TransitiveDependencyManager changes dependency mediation, breaking enforcer rules and scope derivation #12302

@gnodet

Description

@gnodet

Description

Maven 4's default TransitiveDependencyManager (enabled when maven3Personality=false) changes dependency mediation behavior compared to Maven 3's ClassicDependencyManager. This causes enforcer rule violations due to managed version application to transitive dependencies.

### 1. Scope derivation excludes transitive compile deps through provided parents

Update: The projects originally reported under this category (hadoop-api-shim, flink-connector-hive) are not affected by scope derivation changes. Both projects fail because their hadoop-project parent POM (versions 3.1.0 and 3.2.0) contains invalid XML (<Xlint:-unchecked/> — the - after the colon is not a valid XML name start character). Maven 3 silently parses this in lenient mode, while Maven 4 correctly rejects it, causing all transitive dependencies from those POMs to be unavailable. This is a project-side issue, not a Maven 4 regression.

2. Managed version application to transitive dependencies

TransitiveDependencyManager applies <dependencyManagement> versions at ALL depths during collection, not just to direct dependencies. This can downgrade transitive dependency versions, triggering RequireUpperBoundDeps and BannedDependencies enforcer rule violations that pass with Maven 3.

Affected projects: guacamole-client, logging-log4j-samples, netbeans-html4j

Example (guacamole-client):

Require upper bound dependencies error for com.google.code.findbugs:jsr305:3.0.1
+-guacamole-auth-header:1.6.1
  +-guice:5.1.0
    +-guava:32.1.3-jre (managed) <-- guava:30.1-jre
      +-jsr305:3.0.1 (managed) <-- jsr305:3.0.2

Note the (managed) annotations — Maven 4 is applying the parent's dependencyManagement to transitive deps, downgrading jsr305 from 3.0.2 to 3.0.1.

Root cause

TransitiveDependencyManager.manageDependency() applies managed versions/scopes at depth ≥ 2 during collection. Maven 3's ClassicDependencyManager did not do this — version management and scope derivation were handled post-collection in the graph transformer.

Key code difference:

ClassicDependencyManager TransitiveDependencyManager
deriveUntil 2 (root depMgmt only) Integer.MAX_VALUE (all POMs)
Version management sources Root <dependencyManagement> only Every POM in the graph

Workaround

-Dmaven.maven3Personality=true reverts to ClassicDependencyManager behavior.

Suggested fix

Apply TransitiveDependencyManager's full-depth collection only for Maven 4 POMs, or only apply collected managed versions when no version has already been established by a higher-priority (nearer-to-root) source.

Reproducers

# Enforcer mediation issue
git clone https://github.com/apache/guacamole-client.git && cd guacamole-client
mvn -B -e clean package -DskipTests

Context

Found during Maven 4 compatibility testing of Apache projects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions