Chapter 04Lesson 04~110 minutes

Apache Maven Installation, Wrapper, Settings, Local Repository, and Project Bootstrap: Diagnostics, Failure Modes, Security, and Performance

Diagnose Maven wrapper, Java runtime, settings/mirror, local repository, credential, and performance failures with isolated evidence instead of destructive cache cleanup.

DiagnosticsMirror FailureCache IsolationCredentialsPerformance

Learning objectives

  • Apply an evidence-first diagnostic sequence to Maven installation, wrapper, settings, repository, and Java-runtime failures.
  • Recognize wrapper distribution/checksum problems without bypassing integrity verification.
  • Diagnose mirror/proxy failures separately from dependency-coordinate and compiler failures.
  • Use a fresh isolated local repository to test cache hypotheses instead of deleting normal ~/.m2 state.
  • Detect unsafe credential placement and preserve useful diagnostics without exposing secret material.
Version baseline — verified 2026-08-23. The required path uses JDK 21 and Apache Maven 3.9.16. Maven 3.9.16 is the current recommended GA and requires JDK 8+ to execute; Maven 3.10.0-rc-1 and Maven 4.0.0-rc-6 are previews and are not required. Maven Wrapper 3.3.4 is the current stable wrapper. Wrapper examples use the only-script distribution type and pin the Maven distribution with distributionSha256Sum after the downloaded archive has first been verified against Apache's published release checksum/signature. Re-check these versions before applying the examples to production.

1. Use one diagnostic sequence, not random edits

Installation failures often trigger destructive folklore: reinstall Maven, delete ~/.m2, edit the POM, disable TLS/checksum checks, then try again. That destroys evidence and can add new variables.

1. Preserve concise evidence and the exact command.
2. Confirm wrapper / Maven / JDK identity.
3. Inspect wrapper properties and effective settings.
4. Identify requested repository IDs and mirror/proxy policy.
5. Reproduce with a fresh isolated local repository.
6. Inspect plugin/dependency/compiler/test failure only after bootstrap state is known.
7. Apply the smallest correction.
8. Repeat the same controlled command and verify outputs/state.

Each step eliminates a class of causes while keeping the failure reproducible.

2. Failure domain — wrapper downloads a different or untrusted distribution

Review distributionUrl and distributionSha256Sum together. A changed URL is a source change; a changed checksum is an integrity-policy change. Both deserve review. If checksum verification fails, the correct response is to stop and determine why bytes differ—not to delete the checksum property.

git diff -- .mvn/wrapper/maven-wrapper.properties mvnw mvnw.cmd
sed -n '1,160p' .mvn/wrapper/maven-wrapper.properties
./mvnw -v
Security-sensitive: do not “fix” a wrapper checksum mismatch by replacing the expected checksum with the hash of whatever was just downloaded. Re-verify the intended Maven release against Apache's independent checksum/signature first.

3. Failure domain — Maven runs under unexpected Java

A build can fail before project toolchains matter because Maven itself is launched by the wrong Java runtime. Compare ./mvnw -v, java -version, JAVA_HOME, and the CI JDK setup step. If Maven reports a different Java home than expected, fix the launch environment before changing compiler properties.

./mvnw -v
java -version
printf 'JAVA_HOME=%s\n' "${JAVA_HOME:-<unset>}"
command -v java
command -v mvn || true

4. Failure injection — a mirror blocks Central

Use a synthetic invalid domain and a brand-new isolated local repository so the test cannot succeed from cached plugin bytes. The settings file intentionally mirrors only repository ID central to an unreachable address.

<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
  <mirrors>
    <mirror>
      <id>broken-central</id>
      <name>Intentional Chapter 04 failure</name>
      <url>https://repo.example.invalid/maven2</url>
      <mirrorOf>central</mirrorOf>
    </mirror>
  </mirrors>
</settings>
rm -rf .lab/broken-repo
mkdir -p .lab/broken-repo
./mvnw -s .lab/broken-settings.xml \
  -Dmaven.repo.local="$PWD/.lab/broken-repo" \
  -B -ntp \
  org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom

Expected observation: Maven attempts plugin resolution through the selected mirror and fails with a transfer/name-resolution/connectivity error referencing the synthetic mirror. That is a repository-policy/network failure, not a Java compiler or source-code failure.

5. Repair only the failing policy

Return to the clean lab settings from Lesson 2 and repeat the same goal with another fresh repository root. Do not change the POM at the same time; otherwise the before/after comparison no longer isolates the cause.

rm -rf .lab/repaired-repo
mkdir -p .lab/repaired-repo
./mvnw -s .lab/settings.xml \
  -Dmaven.repo.local="$PWD/.lab/repaired-repo" \
  -B -ntp \
  org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom \
  -Doutput=.lab/repaired-effective-pom.xml

If that succeeds while the broken mirror run fails, you have causal evidence that settings/repository routing—not cached project output—caused the failure.

6. Failure domain — stale or corrupt local-repository state

Do not begin by deleting ~/.m2/repository. Reproduce with -Dmaven.repo.local=$PWD/.lab/fresh-repo. If the fresh repository succeeds and the normal repository fails, you have evidence that local mutable state matters. Then inspect only the relevant coordinate/metadata in the disposable or affected repository using Maven/Resolver-aware diagnostics.

Remember that the local repository contains both downloaded cache entries and locally installed artifacts. A locally installed snapshot can make a developer build succeed even when CI cannot obtain the same component remotely.

7. Failure domain — credentials are in the wrong state store

A repository username/password in pom.xml, committed settings.xml, command-line argument, issue screenshot, or build log is not a Maven resolution bug—it is a secret-handling incident. Remove/revoke/rotate the exposed credential first, then move the replacement to protected user/CI settings or another approved secret mechanism.

# Run against the disposable lab, not an employer repository unless authorized.
grep -RniE 'password|token|secret|privateKey|passphrase' . \
  --exclude-dir=.git --exclude-dir=.lab --exclude-dir=target || true
If a real credential was exposed: containment/revocation comes before repository-history cleanup. Removing a string from Git history does not make an already compromised credential safe.

8. Effective settings are diagnostic evidence, not a secret-dump tool

Use help:effective-settings with its default password-hiding behavior and preferably write to a controlled file for review. Never enable password display in shared troubleshooting instructions.

./mvnw -s .lab/settings.xml \
  -Dmaven.repo.local="$PWD/.lab/diagnostic-repo" \
  org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-settings \
  -Doutput=.lab/diagnostic-effective-settings.xml

9. Performance diagnosis — name the phase

Symptom Likely phase Evidence
First run slow, repeat fast Cold plugin/dependency resolution Transfer logs + isolated repository population
Every run slow before compilation Model/plugin setup or remote metadata checks Timestamped log; effective model; transfer activity
Compilation dominates Compiler/source volume Compiler timing/output, not cache deletion
Tests dominate Surefire/test workload Test reports/timing
Wrapper startup slow only on clean machines Maven distribution download/unpack Wrapper home before/after + network evidence

Performance fixes should target the measured phase. A faster warm build is not proof that the build is correctly reproducible.

10. Windows-specific diagnosis

On Windows, compare where.exe java, where.exe mvn, $env:JAVA_HOME, and .\mvnw.cmd -v. A shell can resolve a different executable than an IDE or service account. Preserve the exact environment for the failing process instead of assuming the interactive terminal represents CI.

Knowledge check

A wrapper checksum fails after a dependency-mirror outage. Should you remove distributionSha256Sum to continue?

The build works with ~/.m2/repository but fails with a fresh isolated repository. What does that prove?

The broken mirror test fails before compilation. Why is editing Java source a poor response?

Why can help:effective-settings be safer than printing raw settings files?

A real repository token was committed. What is the first security action?

Why is deleting all of ~/.m2 a weak diagnostic step?

Summary

Maven bootstrap failures become tractable when you preserve evidence and classify the failing layer: wrapper distribution/integrity, Java runtime, settings/mirror/proxy, local repository, project model, or later plugin/compiler/test work. Use isolated state to test hypotheses, change one variable at a time, and never bypass integrity/secret controls merely to obtain a green build.

Next lesson

Prove the complete bootstrap contract

Lesson 5 combines wrapper integrity, isolated repositories, effective settings, deliberate mirror failure, verification, and cleanup into one checkpoint that can be repeated on developer machines or ephemeral CI.

Official references and version notes

The failure examples use synthetic domains and disposable repositories. They are designed to teach classification and recovery without touching production mirrors, credentials, or normal user caches.

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.