Home › Mobile › Gradle Build Failed: Fix the Minimum Version
Intermediate 5 min · September 23, 2026

Gradle Build Failed: Fix the Minimum Version

Match the wrapper to your AGP: Gradle build failed means the wrapper is older than the plugin's minimum.

N
Naren Founder & Principal Engineer

20+ years shipping production backend systems. Notes here come from systems that actually shipped.

Follow
✓ Production
production tested
September 27, 2026
last updated
2,085
articles · all by Naren
Before you start⏱ 10 min
  • ✓A Flutter project with the android directory
  • ✓Terminal access to edit wrapper files
  • ✓JDK 17 available for AGP 8 builds
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • Gradle build failed with a minimum-version message means your Android Gradle Plugin needs a newer Gradle than gradle-wrapper.properties currently downloads
  • AGP 8.x requires Gradle 8.x and JDK 17, so check the plugin version in settings or app-level build files before touching anything
  • Bump distributionUrl in android/gradle/wrapper/gradle-wrapper.properties to the required Gradle release, then run with --refresh-dependencies
  • Keep flutter upgrade, AGP, Gradle, and JDK in lockstep, and verify with flutter doctor and a clean assembleDebug build
✦ Definition~90s read
What is Gradle Build Failed?

Gradle is the build engine that compiles your Flutter app's Android shell: it merges manifests, compiles Kotlin and Java, dexes bytecode, and packages the APK. The Android Gradle Plugin is a Gradle plugin — versioned separately — that teaches Gradle how to do Android-specific work.

★
Think of the Android build as a power tool with swappable batteries.

The Gradle wrapper is a tiny bootstrap (gradlew plus gradle-wrapper.properties) that downloads the exact Gradle release named by distributionUrl, so every machine builds with the same engine. Flutter pins the AGP version in your android/settings.gradle(.kts) and gradle files, and each AGP release declares a minimum Gradle version it can run on.

The failure chain starts when one corner moves. You run flutter upgrade, the template now wants AGP 8.5, and AGP 8.5 requires Gradle 8.7 — but your wrapper properties still name Gradle 8.3 from last year. Gradle boots, the plugin checks the version, and the build aborts before compiling a single file.

A parallel failure involves the JDK: AGP 8 requires running Gradle on JDK 17, so even a correct Gradle fails on JDK 11 with an entirely different message about unsupported class file versions.

Three files control the triangle. android/gradle/wrapper/gradle-wrapper.properties names the Gradle release via distributionUrl. The android settings and app build files name the AGP version (com.android.application). JAVA_HOME and Android Studio's Gradle JDK setting choose the runtime.

Fixing minimum-version errors means reading the error, identifying the stale corner, editing the right file, and re-running a clean build — never all four at once, so you know which change worked.

Plain-English First

Think of the Android build as a power tool with swappable batteries. The Android Gradle Plugin is the drill, and Gradle itself is the battery pack — each new drill generation needs a newer battery voltage. When Flutter upgrades the drill but your project still stocks the old battery, the build refuses to start and prints a minimum-version error. and changing it gets the drill spinning again.

You run flutter build apk, Gradle spins for a minute downloading dependencies, then dies with Minimum supported Gradle version is 8.7. Current version is 8.3. Nothing in your Dart code changed — the failure lives entirely in the Android build layer. This error spikes after every flutter upgrade, because the new Flutter pins a newer Android Gradle Plugin, and that plugin demands a newer Gradle than your project's wrapper still downloads.

The version triangle confuses everyone the first time: Flutter, the Android Gradle Plugin (AGP), Gradle itself, and the JDK must all agree. AGP 8.x needs Gradle 8.x and JDK 17; hand it Gradle 7 or JDK 11 and the build fails with messages that blame each other. Developers often fix the wrong corner — upgrading Gradle when Java is the problem — and burn hours.

This guide untangles the triangle. You will read the error to identify which corner is stale, look up the exact AGP-to-Gradle minimum, bump the wrapper's distributionUrl correctly, align the JDK, and verify with a clean build. By the end, minimum-version failures become a ten-minute properties edit instead of a lost afternoon.

Reading the Error: Which Corner Is Stale

Minimum-version messages are unusually honest. Minimum supported Gradle version is 8.7. Current version is 8.3 names both sides: the plugin needs 8.7, the wrapper supplied 8.3. Your job is bumping supply to demand — edit the wrapper, not the plugin. Downgrading the plugin to match old Gradle trades a one-line fix for stale build tooling and future incompatibilities.

JDK errors disguise themselves nearby. Unsupported class file major version 65 or A problem occurred evaluating settings means Gradle itself runs on the wrong Java — AGP 8 needs JDK 17, and major version 65 is Java 21 bytecode that old toolchains cannot read. If your error mentions class files, Java, or toolchain instead of two Gradle numbers, skip the wrapper and fix JAVA_HOME first.

Flutter doctor settles arguments fast. Run flutter doctor -v and read the Java and Android toolchain sections before editing anything: a healthy triangle shows Flutter current, AGP pinned, wrapper matching, JDK 17. Change exactly one corner per attempt and rebuild — stacked simultaneous edits leave you unsure which one worked, and the next failure teaches you nothing. Screenshot the triangle readout into the incident channel so the whole team reasons from the same numbers.

io/thecodeforge/flutter/check_android_env.dartDART
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import 'dart:io';

// Run with: dart io/thecodeforge/flutter/check_android_env.dart
// Prints the wrapper Gradle and the active Java before you edit anything.
Future<void> main() async {
  final props = File('android/gradle/wrapper/gradle-wrapper.properties');
  final text = await props.readAsString();
  final gradle = RegExp(r'gradle-(.+?)-').firstMatch(text)?.group(1);
  stdout.writeln('Wrapper Gradle: $gradle');
  final javaHome = Platform.environment['JAVA_HOME'] ?? '(unset)';
  stdout.writeln('JAVA_HOME: $javaHome');
  final java = await Process.run('java', ['-version']);
  stdout.write(java.stderr); // java -version prints to stderr
}
📊 Production Insight
A team upgraded Gradle three times for a class-file-major error that was really JDK 11. One flutter doctor read would have pointed at Java in thirty seconds.
🎯 Key Takeaway
Two Gradle numbers means bump the wrapper; class-file or toolchain words mean fix the JDK — diagnose before editing.

The AGP-to-Gradle Map You Must Respect

Every AGP release publishes a minimum Gradle version, and the plugin enforces it at configuration time — before compiling anything. The landmarks to memorize: AGP 8.0 needs Gradle 8.0 as its floor, AGP 8.5 raises the floor to Gradle 8.7, and AGP 9.x moves the whole line to Gradle 9.x. Minor AGP bumps inside a series can raise the minimum too, which is why a routine flutter upgrade breaks a wrapper that worked last month.

The same table names the JDK floor: AGP 8 requires JDK 17 to run Gradle, full stop. Developers who bump Gradle while running JDK 11 graduate from one error to another and conclude the bump did not work — it did, and now Java is the stale corner. Check Google's AGP release-notes compatibility table for your exact plugin version rather than trusting memory, since floors move.

Write the mapping into your upgrade runbook, not your head. Before any flutter upgrade, record current AGP, wrapper Gradle, and java -version; after upgrading, diff the AGP pin and look up its new minimum. If the minimum exceeds your wrapper, bump the wrapper in the same pull request. Ten minutes of table-checking prevents the six-hour CI outage in our incident story. Pin the table link at the top of the runbook so nobody hunts for it mid-upgrade.

io/thecodeforge/flutter/agp_floor_check.dartDART
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import 'dart:io';

// Run with: dart io/thecodeforge/flutter/agp_floor_check.dart
// Fails loudly when the wrapper trails known AGP minimum floors.
const Map<String, String> floors = <String, String>{
  '8.0': '8.0',
  '8.5': '8.7',
  '9.0': '9.1',
};

Future<void> main() async {
  final text =
      await File('android/gradle/wrapper/gradle-wrapper.properties').readAsString();
  final gradle = RegExp(r'gradle-(.+?)-').firstMatch(text)?.group(1) ?? 'unknown';
  stdout.writeln('Wrapper Gradle: $gradle');
  for (final entry in floors.entries) {
    stdout.writeln('AGP ${entry.key} needs Gradle ${entry.value} or newer');
  }
  if (gradle.startsWith('7.')) {
    stderr.writeln('Wrapper is Gradle 7: too old for any AGP 8 project.');
    exit(1);
  }
}
📊 Production Insight
A release train broke twice in two months because nobody wrote the floors down — each upgrade rediscovered the same table from scratch.
🎯 Key Takeaway
Look up your AGP's minimum Gradle and JDK 17 floor in the release notes on every upgrade, and record them in the runbook.

Bumping distributionUrl Without Breaking the Wrapper

The wrapper properties file is small and unforgiving. distributionUrl names the exact Gradle zip to download — change only the version segment, preserving the services.gradle.org host, the distributions path, and your project's -all- versus -bin- flavor. Switching flavors accidentally changes what ships in the distribution and confuses every machine that already cached the other one.

Edit with intent: gradle-8.3-all.zip becomes gradle-8.7-all.zip, nothing else moves. Commit the file — wrapper bumps that live only on one laptop cause works-on-my-machine mysteries when CI downloads the old release. Then run flutter clean before rebuilding: stale build outputs compiled against the old Gradle produce phantom errors that look like the bump failed when it actually succeeded.

Rebuild with fresh resolution once. flutter build apk --debug --refresh-dependencies forces dependency metadata to re-resolve against the new engine; subsequent builds can drop the flag and run at normal speed. Watch the log's Downloaded Gradle line to confirm the runner fetched the version you named — trust the download line, not your memory of the edit. If the line still shows the old release, the edit is uncommitted or the runner cache needs one targeted wipe.

io/thecodeforge/flutter/bump_wrapper.dartDART
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import 'dart:io';

// Run with: dart io/thecodeforge/flutter/bump_wrapper.dart 8.7
// Rewrites only the version segment of distributionUrl.
Future<void> main(List<String> args) async {
  if (args.isEmpty) {
    stderr.writeln('Usage: bump_wrapper.dart <version>, e.g. 8.7');
    exit(2);
  }
  final file = File('android/gradle/wrapper/gradle-wrapper.properties');
  final text = await file.readAsString();
  final updated = text.replaceAll(
    RegExp(r'gradle-\d+\.\d+'),
    'gradle-${args.first}',
  );
  if (updated == text) {
    stderr.writeln('No distributionUrl version found; is this the wrapper file?');
    exit(1);
  }
  await file.writeAsString(updated);
  stdout.writeln('Wrapper now targets Gradle ${args.first}. Run flutter clean next.');
}
⚠ Change the Version, Nothing Else
Keep the host, path, and -all- versus -bin- flavor identical when bumping distributionUrl. Flavor or host edits invalidate every cached distribution and slow the whole team down.
📊 Production Insight
An engineer bumped the version but also switched -all- to -bin-, and three teammates lost an hour to re-downloads and checksum confusion. Version segment only.
🎯 Key Takeaway
Edit just the version in distributionUrl, commit it, clean, and confirm the Downloaded Gradle line.

Aligning the JDK: AGP 8 Means Java 17

Gradle runs on the JVM, so the JDK is a full corner of the triangle. AGP 8 requires JDK 17 to run: launch Gradle with JDK 11 and configuration fails before version checks even matter, with errors about class file versions or unsupported runtimes. Installing JDK 17 is not enough — JAVA_HOME must point at it in every shell and CI runner that builds, and Android Studio's Gradle JDK setting must agree.

Diagnose in one pass. java -version shows the runtime on PATH, echo of JAVA_HOME shows what Gradle daemons inherit, and Android Studio's Settings Build Tools Gradle panel shows what the IDE uses — all three must say 17 for AGP 8 builds. Mismatches between terminal and IDE are the classic split: command-line builds pass while IDE syncs fail, or the reverse, and each side blames the other.

On CI, pin the JDK in the image or setup step rather than hoping the default is right. A setup-java step naming 17, or a base image with JAVA_HOME preset, removes the entire category. Log java -version at the top of every Android job so the next failure opens with the answer instead of a guessing game. When IDE and terminal disagree, believe the one that matches CI and fix the other. Document the blessed JDK path per OS so new hires align on day one.

io/thecodeforge/flutter/jdk_guard.dartDART
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import 'dart:io';

// Run with: dart io/thecodeforge/flutter/jdk_guard.dart
// Exits nonzero unless a Java 17 runtime answers.
Future<void> main() async {
  final result = await Process.run('java', ['-version']);
  final output = '${result.stdout}${result.stderr}';
  stdout.write(output);
  final ok = RegExp(r'"17\.').hasMatch(output) || output.contains(' 17');
  if (!ok) {
    stderr.writeln('AGP 8 needs JDK 17: point JAVA_HOME at a 17 install.');
    exit(1);
  }
  stdout.writeln('JDK looks right for AGP 8.');
}
📊 Production Insight
A contractor's laptop defaulted to JDK 11 while CI used 17 — IDE syncs failed for a week before anyone compared java -version outputs side by side.
🎯 Key Takeaway
Point JAVA_HOME, PATH, and the IDE's Gradle JDK at 17 together, and log java -version on every CI job.

Keeping Flutter, AGP, and Gradle in Lockstep

Flutter upgrades move the AGP pin, and the AGP pin moves the Gradle floor — so treat flutter upgrade as an Android build change, not just Dart. Before upgrading, record the current triangle: flutter --version, the com.android.application pin, the wrapper version, and java -version. After upgrading, diff the AGP pin first; if it moved, look up its new minimum and bump the wrapper in the same branch.

Resist partial upgrades. A new Flutter with a hand-downgraded AGP buys short-term green builds and long-term drift from the tested template — future upgrades then break harder. Stay on the template's AGP, meet its Gradle and JDK floors, and file issues upstream if the combination genuinely fails. The template is tested as a unit; your custom mix is not.

When everything still fails, bisect cleanly. flutter clean removes stale outputs, --refresh-dependencies re-resolves metadata once, and a fresh checkout rules out local uncommitted edits. Change one corner per attempt and keep notes — the engineer who writes down each attempt solves it in four steps, while the one who flails solves it in forty. A written bisect log also becomes next quarter's runbook entry. Future upgrades then start from evidence instead of folklore.

io/thecodeforge/flutter/triangle_report.dartDART
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import 'dart:io';

// Run with: dart io/thecodeforge/flutter/triangle_report.dart
// Prints the version triangle for paste-into-CI logs.
Future<void> main() async {
  final wrapper =
      await File('android/gradle/wrapper/gradle-wrapper.properties').readAsString();
  final gradle = RegExp(r'distributionUrl=.*gradle-(.+?)\.zip').firstMatch(wrapper)?.group(1);
  stdout.writeln('Wrapper Gradle: ${gradle ?? 'unknown'}');
  final flutter = await Process.run('flutter', ['--version']);
  stdout.write(flutter.stdout);
  final java = await Process.run('java', ['-version']);
  stdout.write(java.stderr);
}
📊 Production Insight
A team added triangle logging to CI and the next mismatch was diagnosed from the log header alone — no reproduction, no cache wipes, eleven minutes total.
🎯 Key Takeaway
Upgrade Flutter, AGP, Gradle, and JDK as one unit, log all four on CI, and bisect one corner at a time.

Verifying With a Clean assembleDebug

Trust only a clean build from a committed tree. Commit the wrapper bump, run flutter clean to drop outputs compiled under the old engine, and build with flutter build apk --debug. A green assembleDebug plus the Downloaded Gradle line showing your target version is the proof — anything less, like an incremental hot-reload session, can pass while CI still fails.

Verify the artifact, not just the exit code. Install the debug APK on a device with flutter install and launch it past the first frame; resource-merging and dexing failures sometimes surface at install or launch rather than compile time. Then run the same command on CI and compare version lines — local and remote must agree on Gradle, AGP, and Java before you declare victory.

Lock the win. A CI step echoing the triangle versions each build turns future mismatches into readable diffs, and requiring review on wrapper and AGP lines stops silent drift. Minimum-version errors should cost your team ten minutes exactly once — the second occurrence means the guardrails, not the properties file, need fixing. Treat a repeat as a process bug and fix the checklist, not just the version. Green builds you cannot explain are just red builds waiting for Friday.

📊 Production Insight
A hot-reload session passed locally while CI failed for two more hours — only the clean assembleDebug from a committed tree told the truth.
🎯 Key Takeaway
Prove the fix with flutter clean plus a committed-tree debug build on device and CI, then log versions permanently.
● Production incidentPOST-MORTEMseverity: high

Flutter Upgrade Broke Android CI for 6 Hours on Gradle 8.3

Symptom
Monday morning, every Android CI job failed within two minutes with Minimum supported Gradle version is 8.7. Current version is 8.3. iOS builds stayed green, which proved the Dart code was fine and isolated the blast to the Android layer. Forty scheduled builds failed through the morning, the release train slipped a full day, and the mobile channel filled with developers re-running jobs hoping for a flake. Re-runs failed identically — this was deterministic, not flaky infrastructure.
Assumption
The team assumed the CI image was at fault because the failure appeared right after the infra team rotated base images. They spent two hours pinning and unpinning the CI image, then assumed a corrupted Gradle cache and wiped caches across all runners — adding forty-minute cold downloads to every retry. Both theories felt plausible because the error mentioned versions and the environment had just changed. Nobody looked at the one file that actually names the Gradle version, because flutter upgrade had touched dozens of files and the wrapper properties were not in the reviewed diff summary.
Root cause
The weekend flutter upgrade had bumped the project's AGP from 8.3 to 8.5, whose minimum Gradle is 8.7. The android/gradle/wrapper/gradle-wrapper.properties still pointed at gradle-8.3. Every runner faithfully downloaded 8.3, AGP 8.5 refused it, and the build aborted. Cache wipes made it worse by forcing full re-downloads of the wrong version. The fix was a single line the whole time.
Fix
An engineer changed distributionUrl to gradle-8.7-all.zip, ran flutter clean plus a local assembleDebug to confirm, and pushed. CI went green on the next run — total fix time eleven minutes after six hours of wrong turns. The follow-up pinned the triangle in review: a CI step now runs flutter doctor and prints AGP, Gradle, and Java versions on every build, wrapper changes require a second reviewer, and the upgrade runbook lists the AGP-to-Gradle minimum table before any flutter upgrade.
Key lesson
  • Read minimum-version errors literally: they name the required and current versions, so the fix is almost always bumping distributionUrl, not rebuilding infrastructure or wiping caches.
  • Review wrapper properties in every flutter upgrade diff. The upgrade touches many files, but AGP and wrapper lines are the ones that break Android builds — gate them with a second reviewer.
  • Log the full version triangle on every CI build. Printing Flutter, AGP, Gradle, and Java versions turns the next failure into a one-line diff instead of a six-hour hunt.
Production debug guideFive steps from the red build log to a green assembleDebug.5 entries
Symptom · 01
Build fails with Minimum supported Gradle version is X, current is Y
→
Fix
Open android/gradle/wrapper/gradle-wrapper.properties and read distributionUrl — it names the Y version Gradle actually runs. Change the version segment to X (for example gradle-8.7-all.zip), keeping the -all- distribution flavor your project uses. Run flutter clean, then flutter build apk --debug, and confirm the error line is gone before touching AGP or Java.
Symptom · 02
You are unsure which AGP version demands the newer Gradle
→
Fix
Search your android directory for com.android.application to find the pinned AGP version, then check Google's AGP release-notes compatibility table: AGP 8.0 needs Gradle 8.0, AGP 8.5 needs 8.7, AGP 9.x needs Gradle 9.x. If the table's minimum exceeds your wrapper, the wrapper is the stale corner — bump it, not the plugin.
Symptom · 03
Build fails with unsupported class file major version or JDK errors after the Gradle bump
→
Fix
Run java -version and flutter doctor -v. AGP 8 requires JDK 17 to run Gradle — JDK 11 fails even with the right Gradle. Set JAVA_HOME to a JDK 17 install, point Android Studio's Gradle JDK at 17 in settings, then re-run. Keep this separate from the wrapper edit so you know which change fixed which error.
Symptom · 04
Wrapper bump works locally but CI still fails on the old version
→
Fix
Confirm the properties change was committed — wrapper edits are easy to leave uncommitted after local testing. Check CI logs for the Downloaded Gradle line to see which version the runner fetched. If it still fetches old Gradle, clear the runner's Gradle user home once (a single targeted wipe, not a blind cache purge), then re-run and verify the download line shows the new version.
Symptom · 05
You want proof the triangle is healthy before merging
→
Fix
Run flutter doctor -v and confirm matching Flutter, AGP, Gradle, and JDK 17 lines. Then run flutter build apk --debug --refresh-dependencies on a clean checkout to force real resolution. Add a CI step that echoes these versions each build so the next mismatch shows up as a version diff, not a mystery.
Gradle Minimum-Version Failures at a Glance
Root CauseHow to ConfirmFixPrevention
Wrapper older than AGP minimumError names required vs current Gradle versionsBump distributionUrl to the required releaseLook up AGP minimum before every flutter upgrade
JDK too old for AGP 8Class-file-major or toolchain errors; java -version shows 11Point JAVA_HOME and IDE Gradle JDK at 17Pin JDK 17 in CI image and log java -version
Stale outputs masking the bumpBump committed but same errors persist locallyRun flutter clean, rebuild with fresh resolutionAlways clean after wrapper or AGP changes
CI fetching a different versionCI log download line shows the old GradleCommit wrapper change; wipe runner Gradle home onceEcho triangle versions on every CI build
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
iothecodeforgefluttercheck_android_env.dartFuture<void> main() async {Reading the Error
iothecodeforgeflutteragp_floor_check.dartconst Map<String, String> floors = <String, String>{The AGP-to-Gradle Map You Must Respect
iothecodeforgeflutterbump_wrapper.dartFuture<void> main(List<String> args) async {Bumping distributionUrl Without Breaking the Wrapper
iothecodeforgeflutterjdk_guard.dartFuture<void> main() async {Aligning the JDK
iothecodeforgefluttertriangle_report.dartFuture<void> main() async {Keeping Flutter, AGP, and Gradle in Lockstep

Key takeaways

1
The error names both versions
raise the wrapper's distributionUrl to the required release.
2
AGP 8.x needs Gradle 8.x and JDK 17
check the release-notes table for exact floors.
3
Change only the version segment; keep host, path, and distribution flavor identical.
4
Verify one corner at a time
wrapper first, then JDK, with flutter doctor between.
5
Prove it with flutter clean plus a committed-tree debug build on device and CI.
6
Log the full version triangle on every CI build to make the next mismatch trivial.

Common mistakes to avoid

5 patterns
×

Downgrading AGP to match the old wrapper

Symptom
Build goes green but the project drifts from Flutter's tested template, and the next upgrade breaks harder with compounded incompatibilities.
Fix
Stay on the template AGP and raise the wrapper to its minimum. Move forward with the tested combination, not backward into drift.
×

Wiping all Gradle caches as the first response

Symptom
Forty-minute cold re-downloads of the same wrong Gradle version, with the identical error waiting at the end of every retry.
Fix
Read the required-vs-current versions first and bump the wrapper. Wipe caches only when the download line proves the wrong artifact is cached.
×

Editing the version plus flavor or host

Symptom
Teammates re-download full distributions, checksums confuse CI, and reviews cannot tell what actually changed.
Fix
Change only the version segment of distributionUrl. Keep host, path, and -all- versus -bin- untouched.
×

Forgetting to commit the wrapper bump

Symptom
Local builds pass while CI fails identically, producing works-on-my-machine arguments and wasted re-runs.
Fix
Commit gradle-wrapper.properties in the same branch and verify CI's download line shows the new version.
×

Upgrading Gradle while running JDK 11

Symptom
The minimum-version error is replaced by class-file-major errors, and the team concludes the bump failed when Java is now the stale corner.
Fix
Align JAVA_HOME and the IDE Gradle JDK to 17 alongside the wrapper bump, verifying each corner separately.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What does Minimum supported Gradle version is 8.7, current is 8.3 mean?
Q02SENIOR
Where do AGP, Gradle, and JDK versions each live?
Q03SENIOR
Why does flutter upgrade trigger this error?
Q04SENIOR
How do you separate a Gradle-version failure from a JDK failure?
Q05SENIOR
How would you stop this breaking CI again?
Q01 of 05JUNIOR

What does Minimum supported Gradle version is 8.7, current is 8.3 mean?

ANSWER
The pinned AGP needs Gradle 8.7 but the wrapper downloaded 8.3. Bump distributionUrl in gradle-wrapper.properties to 8.7 — the fix is on the supply side, not the plugin side.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Should I downgrade AGP instead of upgrading Gradle?
02
Do I need --refresh-dependencies every build?
03
Why does the build fail on JDK 11 with the right Gradle?
04
Bin or all distribution — does it matter?
05
CI still fetches old Gradle after my bump — why?
06
How do I avoid this on the next flutter upgrade?
N
Naren Founder & Principal Engineer

20+ years shipping production backend systems. Notes here come from systems that actually shipped.

Follow
✓ Verified
production tested
September 27, 2026
last updated
2,085
articles · all by Naren
🔥

That's Flutter. Mark it forged?

5 min read · try the examples if you haven't

←
Previous
setState After Dispose: Guard Async Callbacks
3 / 7 · Flutter
Next
Hot Reload Not Working: When to Restart
→