Maven Properties, Profiles, settings.xml, Mirrors, Proxies, Servers, and Environment-Specific Builds: Diagnostics, Failure Modes, Security, and Performance
Diagnose environment drift from evidence: unexpected profile activation, over-broad mirrors, mirror/server ID mismatches, proxy failures, leaked secrets, command-line overrides, and warm-cache masking.
Learning objectives
- Apply a fixed evidence-first sequence to profile/settings/repository failures.
- Diagnose an unexpected profile, an over-broad mirror, a proxy/mirror transport error, and a CLI property override without guessing.
- Reproduce a mirror/server-ID authentication failure in a fresh isolated repository and repair only the ID mapping.
- Explain how warm caches can hide upstream removal, authentication, or routing problems.
- Protect credentials during effective-settings and debug-log collection.
~/.m2, global
settings, shared CI settings, or real credentials are modified.
./mvnw, grep, sha256sum, and
shell environment variables. On Windows use mvnw.cmd,
Select-String, Get-FileHash, and
$env:NAME. Maven profile/settings semantics are
cross-platform; file paths and shell quoting are not.
1. Diagnostic sequence — preserve the original cause
Use one sequence repeatedly:
- Preserve concise evidence and exact command.
- Confirm wrapper, Maven, and JDK identity.
- Inspect declared POM and effective POM/settings.
- List active profiles and evaluate the suspect property.
- Inspect dependency/repository IDs and mirror/proxy/server mapping.
- Reproduce with an isolated local repository if cache state is suspect.
- Interpret the first relevant transport/model/plugin error.
- Change one control only.
- Rebuild from controlled state and compare evidence.
This prevents a settings incident from turning into a dependency-version change, cache purge, repository expansion, and credential rewrite all at once.
2. Failure mode — a profile activates unexpectedly on CI
Symptoms may include a changed property, repository, dependency, or plugin execution even though the POM diff looks unrelated. Do not immediately disable profiles globally. Capture activation evidence:
HELP=org.apache.maven.plugins:maven-help-plugin:3.5.2
./mvnw "$HELP:active-profiles" -Doutput=evidence/active-profiles.txt
./mvnw "$HELP:effective-pom" -Dverbose -Doutput=evidence/effective-pom.xml
./mvnw "$HELP:evaluate" -Dexpression=academy.environment -q -DforceStdout
Then inspect whether activation came from -P, settings
activeProfiles, JDK/OS/property/file activation, or
activeByDefault. The fix is to make the intended
condition explicit—not to delete every profile.
3. Failure mode — mirrorOf captures more than intended
A mirror of * can intercept a repository that was
supposed to remain localhost/file-based. A pattern typo such as
whitespace in a comma-separated expression can also produce
surprising matching. Inspect the effective settings and the
repository IDs named by the effective POM.
./mvnw org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-settings -Doutput=evidence/effective-settings.xml
./mvnw org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom -Dverbose -Doutput=evidence/effective-pom.xml
grep -nE '<mirror>|<mirrorOf>|<repository>|<id>|<url>' evidence/effective-settings.xml evidence/effective-pom.xml
Do not “fix” this by adding another public repository. Tighten the mirror expression to the intended IDs or explicitly reviewed exclusions.
4. Intentionally broken example — mirror/server ID mismatch
Reuse Lesson 2's localhost authenticated repository. Keep the server
running and create the intentionally broken settings below. The
credentials are correct but attached to academy-remote;
Maven is actually connecting as mirror academy-mirror.
<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>academy-mirror</id>
<url>http://127.0.0.1:18080/</url>
<mirrorOf>academy-remote</mirrorOf>
</mirror>
</mirrors>
<servers>
<!-- Intentionally wrong: credentials are keyed to the original repository ID,
but Maven authenticates to the selected mirror using the mirror ID. -->
<server>
<id>academy-remote</id>
<username>${env.ACADEMY_REPO_USER}</username>
<password>${env.ACADEMY_REPO_PASSWORD}</password>
</server>
</servers>
</settings>
export REPO_BROKEN="$PWD/.lab-m2-broken/repository"
rm -rf "$PWD/.lab-m2-broken" # disposable lab state only
mkdir -p "$REPO_BROKEN" evidence
set -o pipefail
./mvnw -s lab/settings-broken.xml -Dmaven.repo.local="$REPO_BROKEN" clean package 2>&1 | tee evidence/broken-server-id.log
Expected evidence is an authentication/401-style transfer failure
for the mirrored localhost endpoint. Do not hide it with
|| true. The failure proves transport reached the
expected mirror but did not receive credentials keyed to that mirror
ID.
academy-fixture:1.0.0 were already cached, Maven might
not contact the mirror and the broken credential mapping could
remain invisible.
5. Repair the identity mapping, not the dependency
Change only the <server><id> to
academy-mirror, or restore
settings-good.xml. Keep the same POM coordinates,
dependency version, mirror URL, username, and password. Re-run with
another fresh isolated repository.
export REPO_REPAIRED="$PWD/.lab-m2-repaired/repository"
mkdir -p "$REPO_REPAIRED"
set -o pipefail
./mvnw -s lab/settings-good.xml -Dmaven.repo.local="$REPO_REPAIRED" clean package 2>&1 | tee evidence/repaired-server-id.log
find "$REPO_REPAIRED/dev/academy/fixture/academy-fixture/1.0.0" -maxdepth 1 -type f -print
The success is meaningful because only the identity mapping changed. If the “repair” also changed repository URLs, dependency versions, or cache contents, the root cause would remain ambiguous.
6. Failure mode — proxy or mirror creates misleading resolution errors
Common signals include connection refused, DNS failure, TLS failure, 401/403, or 407 proxy authentication. Interpret the transport layer before changing Maven coordinates. Confirm whether the failing URL is the declared repository, a mirror, or a proxy hop.
| Evidence | Likely layer | First check |
|---|---|---|
| 401/403 from mirror URL | Server credentials / authorization | Mirror ID ↔ server ID and credential scope. |
| 407 | Proxy authentication | Active proxy ID/credentials/nonProxyHosts. |
| TLS/certificate failure | Transport/trust store/proxy interception | JDK trust/runtime + approved endpoint, not dependency version. |
| DNS/connection refused | Network/endpoint | Effective mirror/proxy URL and local fixture process. |
| Artifact not found (404) | Coordinate/repository content | Dependency tree and repository content after routing verified. |
7. Failure mode — a secret is committed or printed
Stop treating the build log as harmless. Effective settings hide passwords by default, but shell scripts can echo environment variables and debug logs can expose sensitive context. If a real credential was committed or printed, rotation/revocation is an incident-response action outside the build fix; deleting the Git line is not sufficient.
git grep -nE '(BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}|<password>[^$<])' -- . || true
grep -R -nF --exclude-dir=.git --exclude-dir=.lab-m2 "$ACADEMY_REPO_PASSWORD" evidence . && echo "Unexpected: disposable secret appeared in files" || echo "PASS: disposable secret not found in captured files"
8. Failure mode — command-line property silently overrides intended value
A CI template may append -D flags far from the project
repository. Capture the exact invocation and evaluate the value
under that invocation:
HELP=org.apache.maven.plugins:maven-help-plugin:3.5.2
./mvnw -s lab/settings-good.xml -Pdev "$HELP:evaluate" -Dexpression=academy.channel -q -DforceStdout
./mvnw -s lab/settings-good.xml -Pdev "$HELP:evaluate" -Dexpression=academy.channel -Dacademy.channel=unexpected-ci-value -q -DforceStdout
The second command should report the CLI value. Fix the CI/template input if that override is unintended; editing the POM default will not beat a higher-precedence invocation property.
9. Failure mode — local cache masks upstream failure
Never begin by deleting normal user state. Create
.lab-m2-diagnostic/repository and reproduce there. If
warm succeeds and isolated fails, you have learned something
concrete: the build depends on local cached state or the current
remote route is unavailable. Preserve both outcomes.
10. Performance — separate resolution from compilation/tests
Mirror/proxy changes primarily affect network resolution. Warm-cache builds may show almost no network time. Compare cold versus warm resolution, then separately measure model construction, compilation, tests, and packaging. A slow proxy should not trigger a compiler tuning change.
11. Compact failure playbook
| Symptom | Evidence | Narrow correction |
|---|---|---|
| Unexpected profile | active-profiles + effective POM | Fix activation source/condition. |
| Wrong mirror selected | effective settings + repository IDs | Narrow/reorder mirror rule. |
| 401 at mirror | mirror ID + server IDs | Match server credential ID to selected mirror. |
| 407 proxy auth | effective proxy config | Correct proxy identity/credential source. |
| Only warm cache works | warm vs isolated repo | Restore remote policy/source; do not bless cache as source of truth. |
| Property differs only in CI | exact command + help:evaluate | Remove/record unintended -D override. |
| Secret in log/repo | secret scan / incident evidence | Rotate/revoke, then remove exposure path. |
Knowledge check
Why does the broken mirror/server lab use an empty local repository?
To force Maven to contact the mirror so authentication behavior is observable instead of masked by a cached dependency.
A build gets HTTP 401 from academy-mirror. What
should you inspect before changing the dependency
version?
The selected mirror ID and matching
servers/server/id credential mapping.
What does a successful warm-cache build prove about current upstream availability?
Very little. It may prove only that required bytes already exist locally.
Why is enabling password display in effective settings a poor default diagnostic step?
You can diagnose routing and server identity from IDs/endpoints while keeping secrets redacted; showing passwords creates unnecessary exposure.
A CI-only -D value changes behavior. Where is the
root cause?
In invocation/CI configuration, not necessarily in the repository POM. Capture and fix the higher-precedence input.
12. Bridge to checkpoint
The diagnostic method now has one job left: integrate the controls. Lesson 5 builds dev and CI variants from the same project, records effective state, proves dependency identity, breaks authentication by ID only, repairs it, and audits evidence for secret leakage.
Official references and version notes
Version-sensitive statements in this lesson were checked against Apache Maven primary documentation on 2026-08-23. The mandatory path uses Maven 3.9.16 through Maven Wrapper 3.3.4, JDK 21 to run Maven, Java 17 as the project release target, Help Plugin 3.5.2, Dependency Plugin 3.11.0, Compiler Plugin 3.15.0, Resources Plugin 3.5.0, Surefire 3.5.6, and JAR Plugin 3.5.1. Maven 4-only profile syntax and preview behavior are not required here.
- Maven — Settings Reference
- Maven — Introduction to Build Profiles
- Maven — POM Reference / Properties
- Maven — Using Mirrors for Repositories
- Maven — Setting up Multiple Repositories
- Maven — Security and Deployment Settings
- Maven — Injecting POM Properties via settings.xml
- Maven Help Plugin 3.5.2
- Maven Dependency Plugin 3.11.0
- Maven Compiler Plugin 3.15.0
- Maven JAR Plugin 3.5.1
- Maven Resources Plugin 3.5.0
- Maven Surefire 3.5.6
- Apache Maven Wrapper
- Maven 3.9.16 Release Notes
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.