Start Debugging

Fix: e: Daemon compilation failed: null in a Flutter Android Gradle build

On Windows, Kotlin incremental compilation fails when the Flutter project and the pub cache sit on different drives. Move PUB_CACHE to the project's drive or turn off IC for pub-cache plugins.

This happens on Windows when your Flutter project is on one drive (D:\) and the pub cache is on another (C:\Users\<you>\AppData\Local\Pub\Cache). Kotlin’s incremental compiler stores every plugin source file as a path relative to your android\ folder. No relative path exists from D:\ to C:\, so compileDebugKotlin crashes for plugins such as shared_preferences_android. The best fix is to put PUB_CACHE on the same drive as your projects, then run flutter clean and flutter pub get. If you cannot do that, set kotlin.incremental=false for the plugin subprojects only (snippet below). On Kotlin Gradle Plugin 2.3.0 and older the APK still builds and the error is only noise. From KGP 2.3.20 (the Flutter 3.44 template) and KGP 2.4.0 (Flutter 3.47) the build can fail outright.

The versions below were checked against Flutter 3.47.5 (Dart 3.13.4, AGP 9.1.0, Gradle 9.3.1, KGP 2.4.0), shared_preferences 2.5.5 / shared_preferences_android 2.4.28, and the Kotlin Gradle Plugin source at tags v1.9.22 through v2.4.20.

The error in context

Reports in flutter/flutter#173456 and flutter/flutter#144566 all look like this, once per plugin:

e: Daemon compilation failed: null
java.lang.Exception
	at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69)
	at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65)
	at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:244)
	...
Caused by: java.lang.AssertionError: java.lang.Exception: Could not close incremental caches in
  D:\src\my_app\build\shared_preferences_android\kotlin\compileReleaseKotlin\cacheable\caches-jvm\jvm\kotlin:
  class-fq-name-to-source.tab, source-to-classes.tab, internal-name-to-source.tab
	at org.jetbrains.kotlin.incremental.IncrementalCachesManager.close(IncrementalCachesManager.kt:55)
	...
	Suppressed: java.lang.IllegalArgumentException: this and base files have different roots:
	  C:\Users\me\AppData\Local\Pub\Cache\hosted\pub.dev\shared_preferences_android-2.4.28\android\src\main\kotlin\io\flutter\plugins\sharedpreferences\LegacySharedPreferencesPlugin.kt
	  and D:\src\my_app\android.

The top line says null because the daemon wraps the real failure in a bare java.lang.Exception with no message. The useful line is the last one: this and base files have different roots. If your log has it, this post is your fix. If it does not, jump to “Lookalikes” at the end.

Why the Kotlin incremental compiler needs one drive

Kotlin incremental compilation (IC) keeps lookup tables under build/<module>/kotlin/compile<Variant>Kotlin/cacheable/caches-jvm. The tables map each source file to the classes it produces. To keep Gradle’s build cache relocatable, Kotlin 1.9.20 started storing those paths relative to a base directory instead of as absolute paths. This is the converter from build-common in the Kotlin repo:

// Kotlin build-common, RelocatableFileToPathConverter.kt (unchanged through 2.4.20)
override fun toPath(file: File): String {
    // ...
    // Note: If the given file is located outside `baseDir`, the relative path will start with "../".
    // It's not "clean", but it can work.
    return file.relativeTo(baseDir).invariantSeparatorsPath
}

For source files, baseDir is the root project directory, which for a Flutter app is <project>\android. Flutter plugins are Gradle subprojects, but their sources live in the pub cache, outside that folder. On macOS and Linux that works, because every path shares the root /. On my Mac, the IC cache for shared_preferences_android actually contains this entry:

../../../../../../../../Users/marius/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.28/android/src/main/kotlin/io/flutter/plugins/sharedpreferences/LegacySharedPreferencesPlugin.kt

On Windows, D:\src\my_app\android and C:\Users\...\Pub\Cache have different roots. No chain of ..\ gets you from one drive to the other, so File.relativeTo throws IllegalArgumentException. The exception fires while IC writes its caches, so it surfaces as “Could not close incremental caches” and the daemon reports it as “Daemon compilation failed”.

That is also why the classic workarounds work: “move the project to C:”, “downgrade Kotlin to 1.9.10” (the last version before relative paths), and “it only fails with some plugins” (only plugins with Kotlin sources go through the Kotlin compiler). JetBrains tracks the root cause as KT-63983, which is still “To be discussed”. A JetBrains engineer noted that the trivial fix (relativeToOrSelf) would cause incorrect build cache hits. The Flutter side is flutter/flutter#105395, open since 2022.

The same crash hits any setup where sources and root project are on different roots: subst virtual drives (KT-65155), a RAM disk build directory, or a WSL path like \mnt\d\project mixed with D:\project.

Why the APK sometimes builds anyway

Many people report that the log is full of e: lines and then prints √ Built build\app\outputs\flutter-apk\app-release.apk. Others, especially since Flutter 3.44, get a real BUILD FAILED. The difference is which compiler path the Kotlin Gradle Plugin takes after the daemon fails. I read it from the KGP source at each tag:

KGP versionDefault compiler pathFallback after the daemon failsResult on a cross-drive project
1.9.20 to 2.3.0GradleKotlinCompilerWorkcompileInProcess, which is explicitly non-incremental (“in-process execution strategy is non-incremental”)Noisy e: output, APK builds
2.3.20 and laterBuild Tools API (kotlin.compiler.runViaBuildToolsApi defaults to true)performCompilation(IN_PROCESS) with the same incremental configuration, including ROOT_PROJECT_DIRFallback hits the same relativeTo, build can fail

The Flutter template pins the KGP version in android/settings.gradle.kts, so your Flutter version at flutter create time decides which row you are in:

Flutter templatetemplateKotlinGradlePluginVersion
3.35.02.1.0
3.38.0, 3.41.02.2.20
3.44.02.3.20
3.47.0 to 3.47.52.4.0

This matches the issue threads. The 2025 reports on Flutter 3.32 and 3.35 say “the APK still builds”. The June 2026 comments say “got this issue after upgrading to Flutter 3.44”. The August 2026 report on 3.47.0 with AGP 9.1.0 and KGP 2.4.0 has :shared_preferences_android:compileDebugKotlin failing the build on a clean run. Those people are not seeing a new bug. The Kotlin fallback that used to hide the old one no longer does.

Minimal repro

You need Windows with two drives (or one subst drive). Keep the default pub cache on C::

# Windows 11, Flutter 3.47.5, default PUB_CACHE on C:
D:
cd \src
flutter create --platforms=android daemon_repro
cd daemon_repro
flutter pub add shared_preferences
flutter build apk --debug

A freshly created 3.47.5 project gets com.android.application 9.1.0, org.jetbrains.kotlin.android 2.4.0 and Gradle 9.3.1, with Kotlin IC on by default. Without the plugin, the template app has nothing outside android\ for Kotlin to compile, so it builds cleanly. That explains the common “it broke as soon as I added one package” observation.

Fix 1: put the pub cache on the same drive as your projects

This is the recommended fix. It removes the cause and keeps incremental compilation everywhere. Pick a folder on the drive where your projects live, point PUB_CACHE at it, and re-resolve:

# Windows, any Flutter 3.x: user-level env var, picked up by new shells and IDEs
[Environment]::SetEnvironmentVariable("PUB_CACHE", "D:\PubCache", "User")

# open a NEW terminal (and restart VS Code / Android Studio), then:
cd D:\src\my_app
flutter clean
flutter pub get
flutter build apk --debug

flutter pub get downloads packages into the new cache and regenerates .dart_tool\package_config.json and .flutter-plugins-dependencies. The Flutter Gradle plugin reads the plugin paths from those files, so every plugin subproject now resolves to D:\PubCache\.... flutter clean matters because the old IC caches under build\ still hold paths from the previous layout. You can delete the old C:\Users\<you>\AppData\Local\Pub\Cache afterwards.

The limit of this fix: if you keep projects on several drives, only one of them can match the cache. For that case, use fix 2.

Fix 2: turn off incremental compilation only for plugin subprojects

Plugins from the pub cache never change between builds, so IC saves you nothing on them. Your own app module is where IC pays off, and its sources are inside android\, so it is not affected. KGP reads kotlin.incremental per project, including project extra properties, so you can scope the switch. Append this to android/build.gradle.kts:

// android/build.gradle.kts, Flutter 3.47.5, AGP 9.1.0, KGP 2.4.0
// Kotlin incremental compilation stores source paths relative to this
// directory. Plugins from the pub cache live outside it, which breaks on
// Windows when the cache is on another drive (KT-63983). Turn IC off for
// those subprojects only; the :app module stays incremental.
subprojects {
    if (!projectDir.canonicalPath.startsWith(rootDir.canonicalPath)) {
        extra["kotlin.incremental"] = "false"
    }
}

For a Groovy android/build.gradle, the equivalent is:

// android/build.gradle, Flutter 3.35 to 3.47
subprojects {
    if (!projectDir.canonicalPath.startsWith(rootDir.canonicalPath)) {
        ext.set("kotlin.incremental", "false")
    }
}

I checked this on macOS against the 3.47.5 repro project by looking at which modules write IC caches after flutter clean && flutter build apk --debug. Without the snippet, both build/app/kotlin/compileDebugKotlin/cacheable/caches-jvm and build/shared_preferences_android/.../caches-jvm exist. With it, only the app one does, and the APK builds. The Groovy version gave the same result. I have no second-drive Windows machine here, so I did not see the Windows crash disappear myself, but the mechanism is the same: with IC off, KGP builds no incremental configuration, and nothing calls RelocatableFileToPathConverter.

Two approaches that look right do not work, and I tried both on 3.47.5:

Setting the property that KGP itself reads is the only per-module switch that survives.

A path dependency inside your repo (path: ../packages/my_plugin) is also outside android\, so the snippet turns IC off for it too. That costs a full recompile of that plugin’s Kotlin on each build, usually a second or two. If that matters, narrow the check to pub cache paths, for example projectDir.canonicalPath.contains("Pub${File.separator}Cache").

Fix 3: turn off Kotlin incremental compilation globally

The bluntest fix, and the one quoted most in the issue threads. In android/gradle.properties:

# android/gradle.properties, any Flutter / KGP version
kotlin.incremental=false

It works, and I confirmed that no caches-jvm folder is created for any module afterwards. The cost is that your app module’s Kotlin also recompiles from scratch on every build. For the Flutter template’s single MainActivity.kt that does not matter. For an app with a lot of native Kotlin (platform channels, a widget, a Wear OS module) it adds up during flutter run. Prefer fix 1 or fix 2 in that case.

What not to do

Lookalikes

Not every Daemon compilation failed line is this bug. Check the Caused by and Suppressed lines:

The raw daemon logs live in android\.kotlin\errors\errors-<timestamp>.log and %TEMP%\kotlin-daemon.*.log. Search them for different roots if the console output is truncated.

Sources

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Back