skip to content

How would you use --warning-mode fail to gate a CI build against new deprecations, and what are the trade-offs?

level: middleimportance: should knowfreq 45%

answer

  1. fail = hard error on deprecation
  2. stay clean continuously
  3. plugin deprecations you can't fix
  4. set in gradle.properties or CLI
  5. adopt only when already clean

basics

~10 s

Run the CI build with --warning-mode fail (or set org.gradle.warning.mode=fail) so any deprecation warning fails the build, preventing new deprecated-API usage from being merged.

solid answer

~40 s

`--warning-mode fail` turns every deprecation warning into a build failure. In CI you either pass the flag on the build command or set `org.gradle.warning.mode=fail` in `gradle.properties`. The payoff is that you stay deprecation-clean continuously: a PR that introduces deprecated-API usage goes red immediately, so the eventual major-version upgrade is trivial instead of a big-bang migration. The trade-off is that **you don't control third-party plugins** — a deprecation emitted by a plugin you depend on will fail your build even though you can't fix it directly. The usual mitigation is to adopt fail-mode only after the build is already clean, pin/upgrade offending plugins, and occasionally keep developers' local builds on `all` (diagnostic) while CI uses `fail` (enforcing). Some teams stage the rollout: warn locally, fail in CI.

code

bash · 3 lines
bash
# CI step: fail the pipeline on any deprecation, even though
# local gradle.properties is set to 'all' for diagnosis.
./gradlew check --warning-mode fail --stacktrace

go deeper

for a junior

Know that fail makes deprecations fail the build and roughly why that's useful.

for a middle

Wire it into CI, explain the plugin-deprecation trade-off and the clean-first adoption order.

for a senior

Design the staged rollout and the local-all / CI-fail split using property-vs-flag precedence.

for a principal

Set org policy mandating fail-mode across repos and a process for handling unfixable plugin deprecations (vendoring, upgrade SLAs).

## The goal: continuous deprecation hygiene Major Gradle upgrades (7→8, 8→9) remove APIs that were deprecated in the prior line. If your build accumulates deprecation warnings unnoticed, the upgrade becomes a multi-week migration. `--warning-mode fail` flips this: it makes any deprecation a **hard build failure**, so deprecations can never silently accumulate. ## Wiring it into CI Two equivalent approaches: ```bash # Explicit on the CI command ./gradlew check --warning-mode fail ``` or persistently: ``` # gradle.properties org.gradle.warning.mode=fail ``` A common pattern is to keep `gradle.properties` on `all` (good for local diagnosis) and pass `--warning-mode fail` only in the CI invocation, so the flag overrides the property in the pipeline. ## Trade-offs and pitfalls 1. **Third-party plugins you can't fix.** If a plugin emits a deprecation, fail-mode breaks your build for something outside your control. You must upgrade or replace the plugin, or temporarily back off to `all` until a fixed version ships. 2. **All-or-nothing granularity.** There is no built-in per-warning allowlist for deprecations via this flag — you cannot say 'fail on mine but ignore that one plugin's'. (Newer Gradle adds problem-reporting APIs, but the simple flag is binary.) 3. **Adoption order.** Turn fail-mode on only *after* the build is already deprecation-clean; otherwise CI is permanently red. ## A staged rollout - Phase 1: `--warning-mode all` in CI logs, fix what you own. - Phase 2: upgrade/replace plugins that emit warnings. - Phase 3: switch CI to `--warning-mode fail` to lock it in. This keeps the team productive while still arriving at a gated, clean state.

  • What breaks fail-mode that you can't directly fix?
    Deprecation warnings emitted by third-party plugins — you must upgrade/replace the plugin or back off to all mode until a fixed version exists.
  • Why adopt fail-mode only after the build is clean?
    Otherwise CI is permanently red from pre-existing deprecations, blocking all merges before anyone can address them.
  • How do you let developers diagnose locally while CI enforces?
    Keep org.gradle.warning.mode=all in gradle.properties for local runs and pass --warning-mode fail explicitly in the CI command, which overrides the property.

It's like treating compiler warnings as errors: cheap to keep clean continuously, painful to retrofit onto a messy build, and occasionally blocked by code you don't own.

saying these in an interview costs you the question

  • Suggesting fail-mode supports a per-warning allowlist via the flag — it doesn't; it's binary.
  • Turning fail-mode on a build that still has warnings and expecting CI to pass.

context