Skip to content

[FGP] Report the real error when applying kotlin-android fails - #195080

Merged
auto-submit[bot] merged 2 commits into
flutter:masterfrom
reidbaker-agent:fgp-kgp-apply-error
Oct 30, 2026
Merged

auto-submit[bot] merged 2 commits into
flutter:masterfrom
reidbaker-agent:fgp-kgp-apply-error

Conversation

@reidbaker-agent

@reidbaker-agent reidbaker-agent commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

When android.builtInKotlin=false and android.newDsl=true, the Flutter Gradle Plugin said "KGP was not found on the classpath". The real error from the Kotlin Gradle Plugin was hidden. The build then failed with an unrelated script compilation error.

This change catches only the missing-plugin case, so other failures show the Kotlin Gradle Plugin's own message.

Related to #181557 and #189236.

Agent authored details

FlutterPluginUtils.detectApplyingKotlinGradlePlugin wrapped pluginManager.apply("kotlin-android") in catch (_: Exception). It now catches org.gradle.api.plugins.UnknownPluginException, which Gradle's DefaultPluginManager.apply(String) throws for an unknown plugin id. Failures inside the plugin's own apply are wrapped differently and now propagate.

Before (AGP 9.3.1, KGP 2.4.20, template app, builtInKotlin=false, newDsl=true):

Applying the Kotlin Android Plugin (KGP) was unsuccessful. KGP was not found on the classpath.
...
* What went wrong:
Script compilation errors:
  Line 41: kotlin {

After:

> Failed to apply plugin 'kotlin-android'.
   > ⛔ Failed to apply plugin 'org.jetbrains.kotlin.android'
     The 'org.jetbrains.kotlin.android' plugin is not compatible with AGP's 9.0 new DSL (`android.newDsl=true` is enabled by default).
     Solution: Set `android.builtInKotlin=true` in `gradle.properties` and migrate to built-in Kotlin (see https://kotl.in/gradle/agp-built-in-kotlin for guidance), or set `android.newDsl=false` in `gradle.properties` to temporarily bypass this issue.

Tests: the two existing "KGP fails to apply" tests now throw UnknownPluginException. Added propagates a KGP failure that is not a missing plugin.

No comments, docs or tests removed.

Verification: ./gradlew test (JDK 17) passed. ktlint 1.5.0 with the CI flags passed. A manual build of the template app was run before and after.

Note: with AGP 9, KGP resolves through AGP even when settings.gradle.kts does not declare it, so the missing-plugin branch is hard to reach in practice.

This applies cleanly to flutter-3.50-candidate.0; FlutterPluginUtils.kt is identical there.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

detectApplyingKotlinGradlePlugin caught every exception from
pluginManager.apply("kotlin-android") and logged that KGP was not on the
classpath. With android.builtInKotlin=false and android.newDsl=true, KGP
throws an incompatibility error that this hid. Catch only
UnknownPluginException so other failures reach the user.
@reidbaker reidbaker added the CICD Run CI/CD label Oct 22, 2026
@github-actions github-actions Bot added platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels. labels Oct 22, 2026
@reidbaker
reidbaker marked this pull request as ready for review October 22, 2026 23:35
@reidbaker
reidbaker requested a review from a team as a code owner October 22, 2026 23:35
if (!pluginState.hasAppPlugin && !pluginState.hasLibPlugin) return@subprojects

if (!isBuiltInKotlinEnabled(project, agpVersion) && !pluginState.hasKgpPlugin) {
// Only a missing plugin is handled here. Any other failure, such as the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment feels super specific but I think that is ok. Other reviewers chime in.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the Kotlin Gradle Plugin (KGP) application logic in FlutterPluginUtils.kt to catch UnknownPluginException instead of a generic Exception when applying kotlin-android. This allows other build failures, such as KGP rejecting specific DSL configurations, to propagate correctly. Corresponding unit tests in FlutterPluginUtilsTest.kt have been updated, and a new test has been added to verify this propagation behavior. There are no review comments, and I have no feedback to provide.

@reidbaker

Copy link
Copy Markdown
Member

@jesswrd I want your opinion on if this should be cherry picked.

@reidbaker

Copy link
Copy Markdown
Member

@reidbaker-agent can you add a comment with the before and after of the log message that users would get?

@reidbaker-agent

Copy link
Copy Markdown
Contributor Author

Here is the exact build output before and after this change for a template Flutter app (flutter create) when android.builtInKotlin=false and android.newDsl=true in android/gradle.properties (where FGP auto-applies kotlin-android and KGP throws because kotlin-android is incompatible with newDsl):

Before this PR

  1. FlutterPluginUtils.detectApplyingKotlinGradlePlugin catches the PluginApplicationException from pluginManager.apply("kotlin-android") and logs the misleading classpath message:
Applying the Kotlin Android Plugin (KGP) was unsuccessful. KGP was not found on the classpath.
If your project uses Kotlin, ensure KGP is declared in the root plugins block.
For more details check: https://docs.flutter.dev/release/breaking-changes/migrate-to-built-in-kotlin
  1. Because the exception was swallowed and kotlin-android failed to apply, Gradle continues evaluating android/app/build.gradle.kts and fails later with an unrelated Kotlin script compilation error on the kotlin { compilerOptions { ... } } block:
FAILURE: Build failed with an exception.

* Where:
Build file '.../android/app/build.gradle.kts' line: 41

* What went wrong:
Script compilation errors:

  Line 41: kotlin {
           ^ None of the following candidates is applicable:
               fun DependencyHandler.kotlin(module: String, version: String? = ...): Any
               fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec

  Line 42:     compilerOptions {
               ^ Unresolved reference 'compilerOptions'.

  Line 43:         jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
                   ^ Unresolved reference 'jvmTarget'.

After this PR

The non-UnknownPluginException failure propagates immediately and prints KGP's actual diagnostic and solution:

FAILURE: Build failed with an exception.

* Where:
Build file '.../android/app/build.gradle.kts' line: 1

* What went wrong:
An exception occurred applying plugin request [id: 'dev.flutter.flutter-gradle-plugin']
> Failed to apply plugin 'kotlin-android'.
   > ⛔ Failed to apply plugin 'org.jetbrains.kotlin.android'
     The 'org.jetbrains.kotlin.android' plugin is not compatible with AGP's 9.0 new DSL (`android.newDsl=true` is enabled by default).
     Solution: Set `android.builtInKotlin=true` in `gradle.properties` and migrate to built-in Kotlin (see https://kotl.in/gradle/agp-built-in-kotlin for guidance), or set `android.newDsl=false` in `gradle.properties` to temporarily bypass this issue.
     See https://kotl.in/gradle/agp-new-dsl for more details.

(When KGP is genuinely absent from the classpath, pluginManager.apply("kotlin-android") throws UnknownPluginException, which still takes the catch block and prints the "KGP was not found on the classpath" message.)

@reidbaker reidbaker added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 29, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 29, 2026
@auto-submit

auto-submit Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/195080, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR.

@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Oct 30, 2026
@reidbaker reidbaker added CICD Run CI/CD autosubmit Merge PR when tree becomes green via auto submit App labels Oct 30, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Oct 30, 2026
Merged via the queue into flutter:master with commit a006537 Oct 30, 2026
30 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 30, 2026
@reidbaker reidbaker added the cp: beta cherry pick this pull request to beta release candidate branch label Oct 30, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Oct 30, 2026
flutter/flutter@c091098...5e805bf

2026-10-30 [email protected] Fix/shared thread merger expired lease (flutter/flutter#194200)
2026-10-30 [email protected] [FGP] Report the real error when applying kotlin-android fails (flutter/flutter#195080)
2026-10-30 [email protected] [Impeller] Minify GLSL shaders (flutter/flutter#195240)
2026-10-30 [email protected] Roll Packages from 0b72e92 to 3742a4e (12 revisions) (flutter/flutter#195686)
2026-10-30 [email protected] Roll Dart SDK from 52c908c00267 to fe609902984b (2 revisions) (flutter/flutter#195679)
2026-10-30 [email protected] Roll Skia from 0789f2ab93b8 to c0c46ee9f938 (1 revision) (flutter/flutter#195671)
2026-10-30 [email protected] Roll Fuchsia Linux SDK from SORPfa9tgFn83M1CR... to x2SqGbVUkOm4d6vk_... (flutter/flutter#195670)
2026-10-30 [email protected] Roll Skia from 4470b8abaad6 to 0789f2ab93b8 (2 revisions) (flutter/flutter#195665)
2026-10-30 [email protected] Roll Dart SDK from 89f7a35480d6 to 52c908c00267 (1 revision) (flutter/flutter#195659)
2026-10-30 [email protected] Roll Skia from 9f4e3117465e to 4470b8abaad6 (4 revisions) (flutter/flutter#195658)
2026-10-30 [email protected] Roll Skia from ec13cd547e98 to 9f4e3117465e (1 revision) (flutter/flutter#195650)
2026-10-30 [email protected] [web] Keep semantics editing state while the text input connection is open (flutter/flutter#195141)
2026-10-30 [email protected] [web_paragraph] Fix multi-span BiDi span order and region direction (flutter/flutter#194980)
2026-10-30 [email protected] [web] Unskip web tests that pass on CanvasKit and Skwasm: accessibility_inspector_test, color_filter_test (flutter/flutter#195541)
2026-10-30 [email protected] Roll Skia from 4ecd22a4a1d0 to ec13cd547e98 (10 revisions) (flutter/flutter#195647)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
auto-submit Bot pushed a commit that referenced this pull request Oct 30, 2026
…ls (#195691)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
#181557

### Impact Description:
Cherry-pick of #195080 (also tracks #189236 and #180137).

On Flutter 3.50 beta (`flutter-3.50-candidate.0`), when an Android project sets `android.newDsl=true` while `android.builtInKotlin=false`, `FlutterPluginUtils.detectApplyingKotlinGradlePlugin` catches all exceptions from `pluginManager.apply("kotlin-android")`. Instead of surfacing the Kotlin Gradle Plugin's actual incompatibility message (`The 'org.jetbrains.kotlin.android' plugin is not compatible with AGP's 9.0 new DSL` along with instructions to set `android.builtInKotlin=true` or `android.newDsl=false`), Flutter Gradle Plugin prints `"Applying the Kotlin Android Plugin (KGP) was unsuccessful. KGP was not found on the classpath."` and the build fails later with an unrelated script compilation error (`Unresolved reference: kotlin` / `compilerOptions`). Narrowing the catch to `UnknownPluginException` surfaces KGP's real error and remediation guidance to developers adopting AGP 9's new DSL in 3.50.

### Changelog Description:
[flutter/181557](#181557): Android builds with `android.newDsl=true` and `android.builtInKotlin=false` misreport a missing Kotlin Gradle Plugin instead of the actual incompatibility error.

### Workaround:
Set `android.builtInKotlin=true` (after migrating off `org.jetbrains.kotlin.android`) or `android.newDsl=false` in `android/gradle.properties`; however, without this fix the build output misleads developers into debugging a missing KGP classpath dependency instead of the `builtInKotlin`/`newDsl` mismatch.

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
1. Create a new Flutter Android app (`flutter create my_app`) using AGP 9.x.
2. Set `android.builtInKotlin=false` and `android.newDsl=true` in `android/gradle.properties`.
3. Run `flutter build apk` and verify that Gradle reports KGP's real error (`The 'org.jetbrains.kotlin.android' plugin is not compatible with AGP's 9.0 new DSL` with remediation steps) instead of `"KGP was not found on the classpath."` (also covered by unit tests in `FlutterPluginUtilsTest.kt`).
gmackall pushed a commit to gmackall/flutter that referenced this pull request Nov 3, 2026
…er#195080)

When `android.builtInKotlin=false` and `android.newDsl=true`, the
Flutter Gradle Plugin said "KGP was not found on the classpath". The
real error from the Kotlin Gradle Plugin was hidden. The build then
failed with an unrelated script compilation error.

This change catches only the missing-plugin case, so other failures show
the Kotlin Gradle Plugin's own message.

Related to flutter#181557 and
flutter#189236.

<details><summary>Agent authored details</summary>

`FlutterPluginUtils.detectApplyingKotlinGradlePlugin` wrapped
`pluginManager.apply("kotlin-android")` in `catch (_: Exception)`. It
now catches `org.gradle.api.plugins.UnknownPluginException`, which
Gradle's `DefaultPluginManager.apply(String)` throws for an unknown
plugin id. Failures inside the plugin's own `apply` are wrapped
differently and now propagate.

Before (AGP 9.3.1, KGP 2.4.20, template app, `builtInKotlin=false`,
`newDsl=true`):
```
Applying the Kotlin Android Plugin (KGP) was unsuccessful. KGP was not found on the classpath.
...
* What went wrong:
Script compilation errors:
  Line 41: kotlin {
```
After:
```
> Failed to apply plugin 'kotlin-android'.
   > ⛔ Failed to apply plugin 'org.jetbrains.kotlin.android'
     The 'org.jetbrains.kotlin.android' plugin is not compatible with AGP's 9.0 new DSL (`android.newDsl=true` is enabled by default).
     Solution: Set `android.builtInKotlin=true` in `gradle.properties` and migrate to built-in Kotlin (see https://kotl.in/gradle/agp-built-in-kotlin for guidance), or set `android.newDsl=false` in `gradle.properties` to temporarily bypass this issue.
```

Tests: the two existing "KGP fails to apply" tests now throw
`UnknownPluginException`. Added `propagates a KGP failure that is not a
missing plugin`.

No comments, docs or tests removed.

Verification: `./gradlew test` (JDK 17) passed. ktlint 1.5.0 with the CI
flags passed. A manual build of the template app was run before and
after.

Note: with AGP 9, KGP resolves through AGP even when
`settings.gradle.kts` does not declare it, so the missing-plugin branch
is hard to reach in practice.

This applies cleanly to `flutter-3.50-candidate.0`;
`FlutterPluginUtils.kt` is identical there.
</details>

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant in-code documentation (doc comments with
`///`).
- [ ] If this PR introduces a new feature or capability, I created and
linked a website documentation issue or PR in [flutter/website] (or
verified none is needed).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

If this change needs to override an active code freeze, provide a
comment explaining why. The code freeze workflow can be overridden by
code reviewers. See pinned issues for any active code freezes with
guidance.

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[flutter/website]: https://github.com/flutter/website
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD cp: beta cherry pick this pull request to beta release candidate branch platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants