Chapter 03Lesson 04~100 minutes

Coordinates, Dependencies, Repositories, Metadata, Transitivity, and Version Selection: Diagnostics, Failure Modes, Security, and Performance

Diagnose missing modules, metadata/artifact failures, version conflicts, cache masking, and repository-origin surprises using evidence before changing configuration or deleting state.

DiagnosticsResolution FailuresCachesRepository OriginConflicts

Learning objectives

  • Apply a repeatable evidence-first sequence to dependency and repository failures.
  • Differentiate coordinate-not-found, metadata failure, artifact-download failure, and version-conflict/runtime failure.
  • Use isolated Maven/Gradle state to detect cache masking without deleting normal user caches.
  • Diagnose repository-origin and ordering surprises from effective configuration instead of adding arbitrary repositories.
  • Connect dependency-resolution performance to cold/warm state, metadata checks, and network/repository behavior without hiding correctness problems.
Version baseline — verified 2026-08-23. Examples use JDK 21 as the common lab runtime, Apache Maven 3.9.16, Apache Maven Wrapper 3.3.4 where a Maven wrapper is already present, Apache Maven Dependency Plugin 3.10.0 for dependency-tree evidence, and Gradle 9.7.1 through the Gradle Wrapper. Maven 4.0.0-rc-6 is still a release candidate and is not required here. The illustrative graph uses org.apache.commons:commons-text:1.10.0, whose published POM declares org.apache.commons:commons-lang3:3.12.0, plus a deliberate direct request for commons-lang3:3.9. Re-check current versions and metadata before reusing these examples in production.

1. Diagnostic sequence: preserve the resolver’s story before changing it

A dependency failure often tempts teams to delete caches, add repositories, or force a version. Those actions destroy evidence or widen the trust boundary. Start by capturing the exact command, wrapper/tool/JDK identity, first causal resolver message, declared/effective repository configuration, and current graph/insight output.

1. Preserve exact failing command + first causal error
2. Confirm ./mvnw -v or ./gradlew -version
3. Inspect declared/effective dependency + repository model
4. Inspect tree/dependencyInsight and requested vs selected versions
5. Classify failure: coordinate | metadata | artifact | auth/TLS | conflict | cache | runtime
6. Reproduce with a new isolated local repository/User Home if cache is suspect
7. Apply the smallest correction at the owning layer
8. Resolve/build again and verify graph + artifact identity

2. Failure A — wrong coordinate or wrong repository

Suppose the artifact ID is mistyped as commons-texxt. The resolver may report that it cannot find the POM/artifact in the configured repository. The first correction is the coordinate—not adding JCenter, a random mirror, or disabling TLS checks.

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-texxt</artifactId>
  <version>1.10.0</version>
</dependency>
dependencies {
    implementation("org.apache.commons:commons-texxt:1.10.0")
}

Repair by restoring the canonical coordinate and rerun in the same isolated state. Preserve the original error in the lab record so the causal chain is visible.

3. Failure B — metadata resolves but artifact bytes fail

A repository can serve a POM or module metadata but fail when the resolver requests the JAR: incomplete proxy synchronization, authorization differences, storage corruption, or a broken hosted repository can cause this. Do not rewrite the version merely because the final file download failed.

Observation Likely layer Next evidence
POM/module metadata 200; JAR 404 repository content/synchronization repository URL/origin + artifact path
metadata 401/403 credentials/repository authorization server/repository ID and secret-store mapping—never print credential
TLS/certificate failure network/trust store/proxy certificate chain + approved proxy configuration
checksum/verification mismatch artifact integrity/origin stop; compare expected metadata and repository origin; do not bypass

4. Failure C — build compiles, runtime behavior changes after version mediation

Conflict resolution can produce a valid classpath that is incompatible with one caller. For example, Gradle selecting a higher transitive version may expose a binary/API behavior change; Maven selecting a nearer older version may deprive another library of a method it expects. The build file can look “valid” while runtime throws NoSuchMethodError or NoClassDefFoundError.

# Maven
./mvnw org.apache.maven.plugins:maven-dependency-plugin:3.10.0:tree   -Dincludes=org.apache.commons:commons-lang3

# Gradle
./gradlew dependencyInsight   --dependency commons-lang3   --configuration runtimeClasspath

Fix by choosing a compatible version intentionally—often by upgrading the requesting libraries together or applying managed/constraint policy—and run tests that exercise the affected runtime path. Do not treat “force whatever makes the error disappear” as a durable solution.

5. Failure D — local cache masks upstream removal or changed metadata

A warm machine can resolve from local state while a new CI agent fails. That discrepancy is evidence. Create a new disposable repository/home and repeat the exact model command. If the isolated run fails, you have proven the build depends on something not currently obtainable under the declared repository contract.

./mvnw -Dmaven.repo.local=.diag-m2   org.apache.maven.plugins:maven-dependency-plugin:3.10.0:tree
GRADLE_USER_HOME="$PWD/.diag-gradle-home" ./gradlew   dependencies --configuration runtimeClasspath
Do not blindly delete: normal ~/.m2/repository, ~/.gradle/caches, wrapper distributions, or organization-shared CI caches. Isolation preserves evidence and prevents collateral damage.

6. Failure E — unexpected repository supplies the module

Repository sprawl can make origin surprising. In Maven, inspect effective settings/POMs and mirror application. In Gradle, inspect settings-level and project-level repositories plus content filters. A repository earlier in one lookup path can supply metadata that determines where artifact bytes are subsequently fetched.

./mvnw help:effective-settings -Doutput=effective-settings.xml
./mvnw help:effective-pom -Doutput=effective-pom.xml
# Review repository IDs/URLs and mirrors; do not print server passwords.
./gradlew dependencies --configuration runtimeClasspath --info
# Use --info only for a disposable/synthetic lab and review output before sharing.
# Never add --debug around real repository credentials without understanding leakage risk.

7. Performance: distinguish resolution work from build execution

A cold isolated resolver may spend most of its time on metadata and artifact downloads. A warm resolver can reuse cached immutable artifacts and metadata. Dynamic/changing versions add periodic metadata checks; shortening their TTL can increase network traffic. Repository managers/proxies can improve locality but introduce their own availability and policy dependencies.

Timing component What changes it Correct optimization question
metadata lookup repository count, dynamic versions, TTL, latency can we reduce mutable discovery and repository sprawl?
artifact download cold cache, artifact size, proxy/CDN can governed proxy/cache serve immutable bytes closer?
graph computation graph size, rules/constraints is graph unnecessarily large/complex?
compile/test/package not dependency resolution itself optimize separately; do not attribute every slow build to downloads

8. Security-sensitive corrections

  • Do not put repository tokens/passwords in POMs, Gradle build scripts, committed gradle.properties, or command history.
  • Do not bypass checksum/signature/dependency-verification failures to “unblock” CI.
  • Do not add unreviewed public repositories or plugin repositories during incident response.
  • Do not enable broad debug logging around real credentials without checking what the tool/plugin emits.
  • When a repository credential may be exposed, rotate/revoke first; cache cleanup does not invalidate the credential.

9. Intentionally broken exercise — diagnose before repair

Change only the Maven or Gradle coordinate from commons-text to commons-texxt. Predict the failure layer. Run the graph command in isolated state. Capture the first meaningful “could not find”/resolution message. Restore the correct coordinate and rerun. Your evidence should show that no repository was added and no global cache was deleted.

Knowledge check

A dependency works on a developer laptop but fails on a brand-new CI agent. What is the first useful hypothesis to test?

Metadata is found but the JAR download fails. Why should you avoid immediately changing the version?

What does NoSuchMethodError after a dependency update often suggest?

Why is adding another public repository a security-sensitive change?

Why is isolated cache testing superior to deleting ~/.m2 or ~/.gradle?

Summary

Dependency failures become tractable when you preserve the resolver’s story: identity, effective repositories, graph requests, selection reason, cache state, and artifact origin. Correct the owning layer with the smallest change, then verify from isolated state. Cache deletion and repository sprawl are not diagnostic methods.

Next lesson

Prove the graph as a production handoff

Lesson 5 combines Maven and Gradle resolution evidence, an intentional conflict policy, isolated dependency state, checksums, prediction, verification, and cleanup into one checkpoint.

Official references and version notes

These lessons were finalized against current primary documentation on 2026-08-23. Dependency metadata, plugin versions, repository policies, Gradle resolution behavior, and Maven/Gradle releases are version-sensitive. Verify the exact tool versions and repository policy used by your project and CI before applying production controls.

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.