Chapter 14Lesson 04~180 minutes

Maven 4 Preview, Build Consumer POM, Compatibility, Migration Planning, and Maven 3 Production Baselines: Diagnostics, Failure Modes, Security, and Performance

Diagnose Maven 4 migration failures involving release-status assumptions, Java runtime, plugin or extension compatibility, consumer metadata changes, and missing rollback evidence.

TroubleshootingJava 17ExtensionsMetadataRelease Governance

Migration failures are valuable when they identify a boundary. They are dangerous when a team suppresses them until the new runtime appears to work. This lesson uses an evidence-first sequence for Maven 4 failures and keeps every repair reversible.

Current status — verified 2026-08-24. Apache Maven 3.9.16 is the current GA Maven 3 baseline. Maven 4.0.0-rc-6, released 2026-08-04, is still not GA and is used here only for compatibility testing. Maven 4 requires Java 17+ to run; the lab uses JDK 21 for both Maven 3 and Maven 4 so the Maven version—not the launcher JDK—is the deliberate variable. Maven Wrapper 3.3.4 remains the stable wrapper baseline. The deliberately broken examples are local fixtures or log-pattern simulations. They never require production repositories, credentials, global settings, or deletion of the normal Maven cache.

Learning objectives

  • Diagnose a Maven 4 RC mistakenly treated as a GA policy baseline.
  • Distinguish a Java launcher incompatibility from a project compiler/toolchain failure.
  • Recognize plugin/core-extension failures caused by removed or internal Maven APIs.
  • Interpret consumer-POM differences as metadata-contract evidence instead of file corruption.
  • Use a fresh isolated local repository before attributing failures to Maven core.
  • Require rollback and output comparison before accepting migration edits.

1. The migration diagnostic sequence

Use the same disciplined order as earlier chapters, with release status added at the front:

  1. Preserve concise error/warning and the exact Maven 3/Maven 4 release identities.
  2. Confirm launcher JDK and wrapper/distribution integrity.
  3. Inspect declared and effective POMs plus mvnup check output.
  4. Inventory active plugins/extensions and lifecycle bindings.
  5. Compare dependency/reactor graph and isolated local-repository state.
  6. Compare test/report/artifact and consumer-POM evidence.
  7. Apply the smallest reversible correction in the candidate lane.
  8. Rebuild under both baselines and decide whether rollback remains viable.

2. Failure mode: release candidate is treated as GA

Symptom: a platform document says “Maven 4 is the new production standard” while the official release history still lists 4.0.0-rc-6 under “not yet GA.” The build may be green; the governance statement is still false.

Repair: classify the Maven 4 lane as compatibility/pre-GA evaluation, retain Maven 3.9.16 as the release baseline, and create a release-status gate that must be re-checked on the migration date. Do not solve a status error with a POM edit.

3. Failure mode: Maven 4 is launched on unsupported Java

Maven 4 requires Java 17+. If the CI image still exposes an older runtime, Maven may fail before meaningful project execution. That is different from a Compiler Plugin message saying the application source/target release is unsupported.

# Preserve identity before touching the POM.
java -version
./mvnw -v

# In CI, inspect JAVA_HOME / PATH selection as environment state.
printf 'JAVA_HOME=%s
' "${JAVA_HOME:-unset}"

Least-destructive repair: update the Maven 4 test lane to a Java 17+ runtime while leaving the application's compiler release/toolchain policy unchanged. Re-run Maven 3 on the same launcher JDK where possible so the Maven-core comparison remains controlled.

4. Intentionally broken example: duplicate plugin declaration

Maven 3.9 can warn about some malformed/duplicate plugin declarations that Maven 4 treats more strictly. This is a useful compatibility fixture because the model itself—not the cache—is wrong.

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <version>3.5.1</version>
    </plugin>
    <!-- Intentionally wrong: same plugin declared twice. -->
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <version>3.5.1</version>
    </plugin>
  </plugins>
</build>

Preserve Maven 3 and Maven 4 outputs. The repair is to merge the intended configuration into one plugin declaration, not to add -X, delete repositories, or downgrade warnings. Then verify both lanes again.

5. Failure mode: plugin or extension uses removed/internal API

A core extension can fail with symptoms such as NoSuchMethodError, ClassNotFoundException, service-loading errors, or bootstrap exceptions before normal lifecycle execution. Treat the exact class/method name as evidence about API coupling.

[ERROR] Failed to load core extension dev.example:legacy-maven-extension:1.2.3
java.lang.NoSuchMethodError: '...internal Maven implementation method...'
    at dev.example.LegacyExtension.initialize(LegacyExtension.java:42)

This is a synthetic log shape, not a claim about a real plugin. The diagnostic action is to identify the exact extension coordinates/source, check its Maven 4 compatibility or upgrade path, and reproduce without production credentials. Removing the extension temporarily can help isolate cause, but only if you understand what functionality/security policy it provided. Do not replace it with an unreviewed third-party fork just to make the test green.

6. Failure mode: consumer POM differs unexpectedly

Symptom: the JAR checksum matches but the installed POM is not byte-identical to the source model 4.1.0 POM. Under Maven 4, that difference can be intentional consumer-POM transformation.

Diagnosis: compare semantic fields: GAV coordinates, packaging, compile/runtime dependency information, exclusions, dependency management where relevant, and repository/publication metadata expected by downstream consumers. Build plugin configuration disappearing from a consumer POM is not itself a defect. A missing runtime dependency would be a defect.

diff -u pom.xml "$ISOLATED_REPO/dev/academy/example/1.0.0/example-1.0.0.pom"   > evidence/build-vs-consumer.diff || true

# Then inspect dependency semantics rather than only textual identity.
grep -E '<modelVersion>|<groupId>|<artifactId>|<version>|<scope>|<dependency>'   evidence/consumer-installed.pom
RC-6 known issue: current release notes describe a BOM consumer-POM issue where property references may remain unresolved. If your project publishes BOMs, record that as a candidate blocker and test the exact BOM output rather than generalizing from a JAR project.

7. Failure mode: migration has no rollback/output comparison

A migration done directly on the main POM, wrapper, CI image, and release job at once has no clean control group. Even if it works, you cannot attribute differences and rollback becomes a reconstruction exercise.

The repair is procedural: restore the Maven 3 baseline from version control, create an isolated candidate branch/copy, pin both runtimes independently, disable production publishing in the candidate, and regenerate build/test/checksum/effective-model evidence. Rollback is a designed state, not a hopeful git revert after artifacts have already been published.

8. Repository/cache diagnostics without destructive cleanup

If Maven 4 resolves something differently or a stale local artifact hides a missing relationship, repeat the failing command with a new disposable local repository. Do not delete ~/.m2/repository. If the fresh repository succeeds/fails differently, you have isolated repository-state influence and preserved the old state for inspection.

./candidate-m4/mvnw   -Dmaven.repo.local="$PWD/.lab/fresh-m4-repo"   -e clean verify | tee evidence/fresh-repo-e.log

Escalate to -X only if narrower evidence is insufficient, and redact repository/server/environment details before sharing logs. Debug verbosity is not a performance benchmark and can expose configuration context.

9. Performance comparisons come after compatibility correctness

Maven 4 may have performance differences in model building, concurrency, or daemon/shell tooling, but this chapter does not accept speed as a reason to ignore semantic differences. First prove the same intended project scope/tests/artifacts. Then measure under comparable local-repository/JDK conditions. A faster RC build that changes artifact metadata is a compatibility finding, not an optimization win.

10. Failure-to-evidence map

Symptom First evidence Likely boundary Least-destructive next step
“Maven 4 is GA” claim conflicts with docs Release history/date Governance/version policy Correct status and retain GA release lane.
Maven 4 fails before project logs java -version, mvnw -v Launcher JDK Use Java 17+ for candidate lane.
Model warning becomes hard failure Declared/effective POM, mvnup check POM validity/changed validation Fix malformed declaration in Maven 3-compatible way first.
Core extension bootstrap error Exact coordinates + exception Extension/internal API Upgrade/replace with reviewed compatible version or block migration.
Installed POM differs Build-vs-consumer semantic diff Consumer metadata Verify downstream contract; do not demand text identity.
Fresh repo behaves differently Isolated resolver log/tree Local repository state Investigate stale/corrupt/locally installed artifact without deleting normal cache.

Knowledge check

A Maven 4 build passes but official history still says not GA. What failed?

What evidence distinguishes a Maven 4 Java-runtime failure from an application target-Java failure?

Should you delete ~/.m2 after a Maven 4 resolution difference?

Why can an installed consumer POM differ from the source POM without being wrong?

What does a NoSuchMethodError in a core extension suggest during migration?

11. Bridge to the checkpoint dossier

Lesson 5 combines these checks into an auditable migration dossier. The output is not “Maven 4 works”; it is a dated decision record containing baseline/candidate identity, compatibility findings, effective-model and artifact comparisons, consumer-POM observations, blockers, release-status assumptions, and exact rollback steps.

Official references and version notes

Version-sensitive statements in this lesson were checked against current Apache Maven primary documentation on 2026-08-24.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.