Chapter 15Lesson 04~180 minutes

Gradle Installation, Wrapper, CLI, Settings, Build Scripts, and Project Bootstrap: Diagnostics, Failure Modes, Security, and Performance

Diagnose bootstrap failures without deleting normal caches: prove executable and JVM identity, inspect Wrapper integrity and settings/build state, isolate global init scripts, and reproduce cache-sensitive behavior in a fresh Gradle User Home.

DiagnosticsWrapper integrityRuntime JVMInit scriptsCaches

Diagnose bootstrap failures without deleting normal caches: prove executable and JVM identity, inspect Wrapper integrity and settings/build state, isolate global init scripts, and reproduce cache-sensitive behavior in a fresh Gradle User Home.

Learning objectives

  • Diagnose system-Gradle versus Wrapper version drift before investigating build logic.
  • Interpret a Wrapper checksum failure as an integrity signal rather than a nuisance to disable.
  • Recognize unsupported Gradle runtime JVMs separately from Java toolchain problems.
  • Prove when a Gradle User Home init script changes build behavior.
  • Use a fresh isolated Gradle User Home to test cache/state hypotheses without deleting normal user state.
  • Apply the course diagnostic sequence and preserve concise evidence.

1. Diagnostic sequence: identity first, then model, then state

  1. Preserve the original command, concise error, and relevant generated/report evidence.
  2. Capture java -version, gradle --version if system Gradle was used, and ./gradlew --version when the Wrapper is trusted.
  3. Inspect Wrapper URL/checksum/JAR integrity and settings/build scripts.
  4. Inspect projects/tasks before blaming dependency or plugin code.
  5. Inspect GRADLE_USER_HOME, project .gradle, daemon state, and repository/network state.
  6. Reproduce with an isolated fresh User Home before deleting anything.
  7. Apply the least destructive correction and verify through the Wrapper.

2. Failure: gradle and ./gradlew are different products in practice

gradle --version
./gradlew --version

If system Gradle reports 9.8.x while the Wrapper reports 9.7.1, that is not “two ways to spell the same command.” Different Gradle releases can have different defaults, deprecations, Kotlin/Groovy runtimes, and plugin compatibility. Reproduce CI through the Wrapper before modifying build scripts.

Repair: restore wrapper-based invocation. If an upgrade is desired, update Wrapper files in a dedicated reviewed change and run the upgrade/deprecation test matrix.

3. Intentionally broken example: distribution checksum mismatch

In a disposable copy, replace the expected checksum with an obviously wrong value and force a fresh lab User Home:

distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
distributionSha256Sum=0000000000000000000000000000000000000000000000000000000000000000
export GRADLE_USER_HOME="$PWD/.checksum-failure-home"
./gradlew --version
# Expected: Wrapper download verification fails; do not disable verification.

The original cause is not “Gradle cache corruption.” The configured trust assertion does not match the downloaded distribution. Restore the reviewed official value acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a, remove only .checksum-failure-home, and retry.

4. Failure: unsupported Gradle runtime JVM

Gradle 9.7.1 requires JVM 17–26 for running Gradle. Launching it with Java 11 is a build-engine bootstrap failure even if the project itself targets Java 11 or 17.

java -version
./gradlew --version
# If JAVA_HOME points to an unsupported runtime, fix the Gradle runtime JVM.
# Do not "repair" this by changing sourceCompatibility or the Java toolchain.

Toolchain configuration controls Java compile/test tasks. It does not make an unsupported JVM capable of hosting Gradle itself. Keep runtime-JVM and compiler-toolchain incidents separate.

5. Failure: a global init script changes the project before settings/build logic

# DISPOSABLE isolated home only
mkdir -p "$GRADLE_USER_HOME/init.d"
cat > "$GRADLE_USER_HOME/init.d/lab-policy.init.gradle.kts" <<'EOF'
beforeSettings {
    throw GradleException("LAB: injected init-script policy")
}
EOF

./gradlew help --console=plain
# Expected: build stops before normal project configuration.

mv "$GRADLE_USER_HOME/init.d/lab-policy.init.gradle.kts"    "$GRADLE_USER_HOME/init.d/lab-policy.init.gradle.kts.disabled"
./gradlew help --console=plain

The failure proves that Gradle User Home is executable configuration state. On a real workstation, inspect $GRADLE_USER_HOME/init.gradle(.kts) and init.d/; do not delete the home because you have not yet established whether the script is intentional organizational policy.

6. Failure hypothesis: stale user/project state masks the problem

Suppose a dependency resolution failure appears only on one machine. Deleting ~/.gradle destroys evidence and unrelated caches. Instead compare the same command with a fresh isolated home:

mkdir -p .fresh-gradle-home
GRADLE_USER_HOME="$PWD/.fresh-gradle-home" ./gradlew help --console=plain
GRADLE_USER_HOME="$PWD/.fresh-gradle-home" ./gradlew build --console=plain

If the fresh home succeeds, you have evidence that user-home configuration/cache state matters. Compare init scripts, gradle.properties, daemon JVM, cached metadata, and repository access. If both fail identically, stop blaming the cache and return to model/network/plugin evidence.

7. Project .gradle is different from the Gradle User Home

A project-local .gradle/ directory contains project-specific incremental/configuration state. A user-home caches/modules-2 area contains downloaded dependency metadata/artifacts. A build build/ directory contains task outputs. Clearing one does not mean the same thing as clearing another.

When cleanup is truly justified, copy/preserve the failure evidence first and delete only the smallest disposable state that tests the hypothesis.

8. Debugging without turning logs into a credential leak

Gradle offers --stacktrace, --info, and --debug. Escalate gradually. Debug logs can contain environment, repository, path, and configuration detail that should not be uploaded blindly.

./gradlew build --stacktrace --console=plain
./gradlew build --info --console=plain
# Use --debug only when needed, and review/redact before sharing.

Prefer focused reports and exact error sections over attaching complete daemon logs to public tickets.

9. Performance diagnosis: cold, warm, daemon, and task work are different variables

A first Wrapper run may include Gradle distribution provisioning. A first build may resolve dependencies and compile scripts. A warm build may reuse user-home/project caches and a daemon. Those are different costs. Do not call a cache deletion a “performance test” unless you state what state was removed and why.

Chapter 23 will examine Gradle performance/cache mechanisms deeply. Here the operational lesson is smaller: record whether the User Home is fresh or warm and whether the daemon is present before comparing timings.

10. Security-sensitive bootstrap actions

Changing distributionUrl, distributionSha256Sum, the Wrapper JAR, global init scripts, Gradle User Home properties, plugin repositories, or runtime-JVM provisioning changes trust boundaries. Review those changes independently from application code.

Never “solve” a checksum mismatch by removing the checksum. Establish the intended release and expected digest from Gradle’s official checksum source, then reconcile why the bytes differ.

Knowledge check

A checksum mismatch disappears after deleting distributionSha256Sum. Is the incident fixed?

Why is Java 11 failing to launch Gradle 9.7.1 not a Java toolchain problem?

A build fails before settings.gradle.kts behavior is visible and succeeds with a fresh User Home. What should you inspect?

Why avoid deleting normal ~/.gradle first?

When should you use --debug?

11. Bridge to the checkpoint

The final lesson turns this into an acceptance exercise: bootstrap with a trusted installed Gradle, verify Wrapper JAR and distribution checksums, build through an isolated User Home, compare accidental system invocation, then introduce a settings error and diagnose it without touching normal machine state.

Official references and version notes

Version snapshot: These lessons were generated for August 24, 2026 with Gradle 9.7.1 as the pinned lab release. Re-check the official release and compatibility pages before copying version-specific pins into a future production repository.

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.