Flutter Android build fails with Namespace not specified after AGP 8 upgrade
A new Android Studio with JDK 21 forced a Gradle upgrade, the Gradle upgrade pulled in AGP 8, and AGP 8 rejected two old Flutter plugins with Namespace not specified. How we untangled the Gradle, AGP, Kotlin and JDK chain.
It started with a laptop refresh. A developer on our grocery delivery app set up a new MacBook with the current Android Studio, Ladybug, and the Flutter app that built fine on everyone else's machine failed immediately:
FAILURE: Build failed with an exception.
* What went wrong:
Could not open cp_settings generic class cache for settings file '.../android/settings.gradle'.
> BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_' Unsupported class file major version 65
Class file major version 65 is Java 21. Ladybug bundles JDK 21, Flutter uses Android Studio's JDK by default, and our project was on Gradle 7.6.3, which cannot run on Java 21. The Flutter docs suggest upgrading Gradle, and Android Studio's AGP Upgrade Assistant offered to go all the way. We accepted Gradle 8.10.2 and AGP 8.7.2. The next build failed differently:
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring project ':store_hours_native'.
> Could not create an instance of type com.android.build.api.variant.impl.LibraryVariantBuilderImpl.
> Namespace not specified. Specify a namespace in the module's build file:
/Users/dev/.pub-cache/git/store_hours_native-1f0c.../android/build.gradle.
See https://d.android.com/r/tools/upgrade-assistant/set-namespace for information about setting the namespace.
Reproducing it
The failure is deterministic once the versions line up:
- Use AGP 8.0 or newer in
android/settings.gradle. - Depend on a Flutter plugin whose
android/build.gradlehas nonamespacein itsandroid {}block and relies on thepackageattribute in itsAndroidManifest.xml. - Run
flutter build apk --debug.
What we ruled out
- Our own app module. The app's
android/app/build.gradlealready hadnamespace "com.example.grocer"; Flutter's templates have included it for a while. The error named a plugin project, not:app. - A corrupted pub cache.
flutter pub cache repairand a clean checkout changed nothing. - Flutter itself. Flutter 3.24.4 supports AGP 8 and Gradle 8; a fresh
flutter createproject with the same versions built fine.
Root cause
AGP 8 removed support for reading a library's namespace from the package attribute in its manifest.
Every Android module must declare namespace in its Gradle file. Two of our plugins predated that
requirement: store_hours_native, an in-house plugin we had not touched in three years, and an
unmaintained third-party PDF viewer pinned to a 2021 release. Upgrading the build toolchain was
correct; our plugins were simply not ready for it.
What is happening under the hood
The namespace is the Java/Kotlin package used for the generated R and BuildConfig classes.
Before AGP 7.3, it came from package="..." in AndroidManifest.xml. AGP 7.3 introduced namespace
in the DSL as the preferred source, and AGP 8.0 made it mandatory. Flutter plugins are Gradle
library modules, so each plugin's Android project is subject to the same rule as your app.
The upgrade was really a chain of constraints, and each link forced the next:
| Link | Constraint we hit |
|---|---|
| Android Studio Ladybug | Bundles JDK 21 |
| JDK 21 | Gradle 8.5 or newer needed to run on it |
| AGP 8.7 | Requires Gradle 8.9+ and JDK 17+ |
| AGP 8 | Every module needs namespace |
| Kotlin Gradle plugin with JDK 17 | Java and Kotlin JVM targets must match |
That last row produced our third error, from the PDF plugin once the namespace was fixed:
Execution failed for task ':pdf_view_legacy:compileDebugKotlin'.
> Inconsistent JVM-target compatibility detected for tasks 'compileDebugJavaWithJavac' (1.8) and 'compileDebugKotlin' (17).
The plugin set compileOptions to Java 8 but did not set kotlinOptions.jvmTarget, so Kotlin
defaulted to the toolchain version.
Environment
| Component | Version / value |
|---|---|
| macOS | 15.1, Apple Silicon |
| IDE | Android Studio Ladybug 2024.2.1 (bundled JDK 21) |
| Flutter | 3.24.4 stable, Dart 3.5.4 |
| Gradle | 7.6.3 before, 8.10.2 after |
| AGP | 7.3.0 before, 8.7.2 after |
| Kotlin Gradle plugin | 1.7.10 before, 1.9.25 after |
| Problem plugins | in-house store_hours_native (git dependency), pdf_view_legacy 1.2.0 |
Minimal reproduction
// A plugin's android/build.gradle that worked on AGP 7 and fails on AGP 8
apply plugin: 'com.android.library'
android {
compileSdkVersion 31
defaultConfig { minSdkVersion 21 }
// no namespace: AGP 8 refuses to configure this module
}
<!-- android/src/main/AndroidManifest.xml of the same plugin -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.storehours" />
Who is affected
Any Flutter app that moves to AGP 8 or newer while depending on a plugin that has not declared a namespace. Most popular plugins fixed this in 2023, so the usual culprits are in-house plugins, forks, and discontinued packages. React Native and native Android projects with old library modules hit the same error.
The fix
1. Pin the toolchain deliberately in Flutter's declarative plugin block, instead of leaving it to whatever the IDE suggests:
// android/settings.gradle
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.7.2" apply false
id "org.jetbrains.kotlin.android" version "1.9.25" apply false
}
# android/gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
2. Fix the in-house plugin properly. We own it, so we added the namespace, removed the manifest
package attribute, and aligned JVM targets:
android {
+ namespace "com.example.storehours"
compileSdk 34
defaultConfig { minSdk 21 }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
+ }
+ kotlinOptions { jvmTarget = "17" }
}
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.storehours" />
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" />
We tagged a new version of the plugin's git repository and bumped the ref in pubspec.yaml.
3. Replace or fork the abandoned plugin. We checked pub.dev for a maintained alternative that covered our use (viewing a receipt PDF) and migrated two screens to it. Had there been none, we would have forked it into our organisation and used a git dependency with the same two-line fix:
# pubspec.yaml (fork option, not what we shipped)
dependency_overrides:
pdf_view_legacy:
git:
url: https://github.com/example-org/pdf_view_legacy.git
ref: agp8-namespace
4. Make the JDK explicit so every machine and CI agent uses the same one:
flutter config --jdk-dir="/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home"
flutter doctor -v | grep -i "java version"
We chose JDK 17 for now because it is what our CI image ships, and AGP 8.7 with Gradle 8.10 is also fine on 21.
Alternatives and trade-offs
- Inject a namespace from the root
build.gradle. A widely shared snippet setsandroid.namespacefor every library subproject in anafterEvaluatehook. It works, but it hides plugins that need attention, can pick a wrong namespace, and must be placed before Flutter'sevaluationDependsOn(":app")line or Gradle complains that the project is already evaluated. We treat it as an emergency measure only. - Point Flutter at an older JDK and stay on AGP 7. This unblocks a laptop in a minute and was our first workaround. It only postpones the migration; Play's target SDK requirements will eventually need newer AGP versions anyway.
- Upgrade Flutter first. Newer Flutter releases bump template versions and warn about outdated Gradle, AGP and Kotlin versions, which makes the chain visible earlier. It does not fix third-party plugins.
How to test the fix
flutter clean
flutter pub get
cd android && ./gradlew --version && cd ..
flutter build apk --release
flutter build appbundle --release
We ran the same commands on a CI agent with JDK 17 and on the Ladybug laptop with its bundled JDK 21.
Both produced identical versionCode and app sizes within a few kilobytes, and our integration tests
passed on a Pixel 7 emulator.
Confirming in production
- The release built from the upgraded toolchain went through Play's pre-launch report with no new crashes or warnings.
- Crash-free users on Android stayed at 99.6 percent after a full rollout.
- The receipt viewer, the screen most at risk because we replaced its plugin, had no new crash clusters in Crashlytics and its open rate matched the prior version.
Regression guard
- CI now fails the build when
flutter doctor -vreports a Java version other than the one pinned in our.tool-versions. - A script in CI lists every plugin's
android/build.gradlefrom.flutter-plugins-dependenciesand fails if any lacks anamespaceline, so the next AGP bump does not surprise us. - Dependabot opens weekly pull requests for pub packages, and a monthly task reviews any plugin marked as discontinued on pub.dev.
Security implications
None beyond the bug itself. Upgrading AGP and Gradle picks up security fixes in the build toolchain, which is a positive side effect. Replacing an unmaintained plugin also removes native code nobody was reviewing. If you fork a plugin, own its updates; a fork that is never rebased becomes the next abandoned dependency.
Prevention checklist
- Upgrade Gradle, AGP, Kotlin and the JDK together, using the official compatibility tables.
- Pin the JDK used by Flutter with
flutter config --jdk-diron every machine and in CI. - Check plugins for
namespacesupport before raising AGP. - Retire discontinued plugins early instead of pinning them.
- Do not leave global namespace-injection hacks in the root build file after the emergency.
References
- Android Developers: Set the namespace — https://developer.android.com/build/configure-app-module#set-namespace
- Android Developers: AGP release notes and compatibility — https://developer.android.com/build/releases/gradle-plugin
- Gradle: Compatibility matrix — https://docs.gradle.org/current/userguide/compatibility.html
- Flutter: Android Java Gradle migration guide — https://docs.flutter.dev/release/breaking-changes/android-java-gradle-migration-guide
- Flutter: Deprecated imperative apply of Flutter's Gradle plugins — https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply
Add a label
Embed this post
<iframe src="https://hibug.me/flutter-android-namespace-not-specified-agp-8" width="700" height="420" frameborder="0" loading="lazy"></iframe>
I have spent most of my career on the side of software that pages people at night: payment integrations, web platforms with real traffic, CI/CD pipelines, Kubernetes clusters and the databases underneath them. Somewhere along the way I started keeping a notebook of every bug that cost more than an hour — the exact error, what we ruled out, the real root cause and how we proved the fix. Hibug is where those notes live. Every post follows the same path: Investigate, Explain, Fix, Verify — with the environment spelled out, the fix tested, and the security angle checked.
Comments
0No comments yet. Be the first to comment!
Sign In to post a comment.