Sonar Scanner 7.3.0: AGP 9 MissingValueException Root Cause, CLI Workaround & Coverage Trade-offs

Hello SonarSource team,

After extensive debugging on an AGP 9.2.0 codebase, we managed to track down the exact trigger for the MissingValueException crashing the :sonarResolver task, and we found a clean workaround that doesn’t require mutating Gradle scripts (though it does come with a temporary trade-off).

The Root Cause

The crash happens specifically because of how sonarResolver interacts with Firebase Crashlytics (and potentially other plugins like Google Services) under AGP 9’s strict lazy configuration.

  1. When sonar.android.variant is set (e.g., stagingDebug), Sonar asks AGP for the variant’s generated resource directories.

  2. AGP provides a list of lazy providers, including the output directory for injectCrashlyticsMappingFileId.

  3. In many local/debug builds, developers disable Crashlytics mapping uploads (e.g., mappingFileUploadEnabled = false).

  4. Because the Crashlytics task is disabled, it intentionally produces no value for that provider.

  5. When sonarResolver eagerly queries the provider collection, Gradle 9 strictly enforces provider constraints and crashes the build with: Cannot query the value of this provider because it has no value available.

This perfectly aligns with the architectural fixes being discussed in PR #498.

The Clean Workaround (No build script hacks)

Initially, we tried forcing explicit dependsOn relationships in our Gradle scripts to bypass the lazy evaluation errors, but this caused massive side-effects with KSP, Hilt, and further AGP 9 lazy-evaluation crashes (Catch-22s where Gradle refuses to query providers before upstream tasks complete).

The safest workaround to survive AGP 9 until the plugin is updated is to bypass the sonarResolver task entirely via the CLI for the affected module:

Bash

./gradlew sonar -x :app:sonarResolver -Dsonar.java.binaries=build

*(Note: The -Dsonar.java.binaries=build flag prevents the Java analyzer from crashing if it encounters legacy .java files but no compiled classes in the old AGP 7/8 directories).
*
I think there is an open discussion for that topic here: Sonar-scanner-gradle 7.3.0: Incorrect sonar.java.binaries

The Trade-off: Missing Code and Coverage for the Excluded Module

It is important to note that bypassing :app:sonarResolver comes with a cost: SonarCloud will effectively ignore the :app module.

Because the resolver doesn’t run, Sonar is never told where the :app module’s source code or JaCoCo XML reports live. As a result, your dashboard will show (missing) for Lines of Code and Test Coverage for that specific module.

Why this is still worth it: In a modern multi-module architecture, this is usually an acceptable temporary compromise. Even though the :app module is skipped, your :core, :feature, and library modules will still be successfully configured, analyzed, and uploaded. This keeps the CI pipeline green and the vast majority of the codebase monitored while we wait for the official plugin patch.

I hope this context helps the engineering team validate the fixes for AGP 9!

Hello @Gustavo_Morales,

Thank you for the feedback and your very detailed report on the latest version of the scanner for Gradle !

I have created a ticket for us to fix the issues with missing dependencies in the SonarResolverTask and another one to fix problems with the computation of compiled classes.
As you have mentioned, we are aware of the issues with the computation of properties at configuration time and planning to move this logic to the execution phase.

Best regards,
Aurélien