What React Native libraries do you use?
Hermes, RN New Architecture, React Native without Frameworks
Are you using sentry.io or on-premise?
sentry.io (SaS)
Are you using any other error monitoring solution alongside Sentry?
Yes
Other Error Monitoring Solution Name
Datadog (@datadog/mobile-react-native) and Luciq (@luciq/react-native). Noted because both ship Gradle scripts with the same Configuration Cache incompatibility — this report is scoped to Sentry's.
@sentry/react-native SDK Version
8.19.0 (latest). Confirmed via a Configuration Cache build failure on 8.10.0; the code responsible is present verbatim in 8.19.0's sentry.gradle.kts (line references below), so it applies to latest — I have inspected the source but not re-run a build on 8.19.0.
How does your development environment look like?
Gradle: 9.0.0 (Configuration Cache is the recommended execution mode; Gradle prints this on every build)
AGP: 8.x
React Native: 0.83.9, Hermes enabled, newArchEnabled=true
Build: ./gradlew :app:bundleRelease (release AAB; observed on Linux CI, ubuntu-24.04)
Sentry.init()
Sentry.init({
dsn: 'https://...@sentry.io/...',
// standard options; the failure is at build time, independent of runtime init options
});
Steps to Reproduce
- Set
org.gradle.configuration-cache=true in android/gradle.properties
- Set
org.gradle.configuration-cache.problems=warn (to get past warn-level problems and surface the hard failures)
./gradlew :app:bundleRelease (or any release bundle/assemble)
Expected Result
The build succeeds with Configuration Cache enabled (stores an entry on the first run, reuses it — and skips the configuration phase — on subsequent runs).
Actual Result
problems=warn does not rescue these — they are hard execution-time exceptions (this is also what #4252 reported, with warn mode set):
* What went wrong:
Could not evaluate onlyIf predicate for task
':app:createBundleReleaseJsAndAssets_SentryUpload_<pkg>@<version>+<code>'.
> Could not evaluate spec for 'Task satisfies onlyIf closure'.
The same failure also occurs for :app:copySentryJsonConfiguration.
Root cause
Line references are to packages/core/sentry.gradle.kts on main (shipped in 8.19.0); the Groovy sentry.gradle in 8.10.0 has the identical constructs.
1. onlyIf predicates call closures resolved from project's extra properties, and are evaluated at execution time.
// sentry.gradle.kts
fun shouldCopySentryOptionsFile(): Boolean {
val closure = extra["shouldCopySentryOptionsFile"] as groovy.lang.Closure<*> // L87 — reads project state
return closure.call() as Boolean
}
tasks.register("copySentryJsonConfiguration") { // L103 (unconditional)
onlyIf { shouldCopySentryOptionsFile() } // L104 — evaluated at execution time → project access
...
}
Also onlyIf { shouldCopySentryOptionsFile() } at L159 and onlyIf { shouldSentryAutoUploadGeneral() } at L561 (the *_SentryUpload task). onlyIf runs at execution time; resolving the extra-property closure there is the CC violation.
2. copySentryJsonConfiguration's doLast touches project at execution time.
doLast {
val appRoot = project.rootDir.parentFile ?: project.rootDir // L106 — project at execution time
...
copy { from(sentryOptionsFile); into(androidAssetsDir); ... } // L113 — project.copy at execution time
}
3. *_SentryUpload uses project.logger at execution time (e.g. L594, L596, and elsewhere in its actions). The CLI invocation itself already uses the CC-safe injected ExecOperations (InjectedExecOps, defined L76, instantiated L577) — so only these residual project accesses remain.
Why the usual escape hatches don't work
- Upgrading to the 8.14.0+
.kts rewrite (#6119) does not help — verified by reading sentry.gradle.kts on main: it is a syntax migration, the CC-relevant constructs above are unchanged.
- Env-var gating (
SENTRY_DISABLE_AUTO_UPLOAD=true, SENTRY_COPY_OPTIONS_FILE=false) does not help: copySentryJsonConfiguration is registered unconditionally (L103) and wired unconditionally via preBuild.dependsOn("copySentryJsonConfiguration") in afterEvaluate (L781–782), so it is always in the task graph and its onlyIf is always evaluated. The env var only changes the predicate's result, not whether the failing evaluation runs.
Proposed minimal fix (interim, ahead of #796)
All CC-safe patterns, no behaviour change:
-
onlyIf (L104, L159, L561) — capture the env read at configuration time and reference the captured boolean:
val copyOptionsFile = System.getenv("SENTRY_COPY_OPTIONS_FILE") != "false"
val autoUploadGeneral = System.getenv("SENTRY_DISABLE_AUTO_UPLOAD") != "true"
// ...
onlyIf { copyOptionsFile }
onlyIf { autoUploadGeneral }
(System.getenv at configuration time is a tracked CC input.)
-
project.rootDir (L106) — capture at configuration time and use the local in doLast.
-
copy {} (L113) — use an injected FileSystemOperations (same injection pattern already used for ExecOperations), or java.nio.file.Files.copy for the single-file case.
-
project.logger (L594/L596/actions) — use the task's own logger instead of project.logger (the task logger is CC-safe).
I'm happy to open a PR with these changes as an interim step before the full SAGP migration in #796 — let me know if you'd prefer to fold it directly into that work instead.
References
What React Native libraries do you use?
Hermes, RN New Architecture, React Native without Frameworks
Are you using sentry.io or on-premise?
sentry.io (SaS)
Are you using any other error monitoring solution alongside Sentry?
Yes
Other Error Monitoring Solution Name
Datadog (
@datadog/mobile-react-native) and Luciq (@luciq/react-native). Noted because both ship Gradle scripts with the same Configuration Cache incompatibility — this report is scoped to Sentry's.@sentry/react-native SDK Version
8.19.0 (latest). Confirmed via a Configuration Cache build failure on 8.10.0; the code responsible is present verbatim in 8.19.0's
sentry.gradle.kts(line references below), so it applies to latest — I have inspected the source but not re-run a build on 8.19.0.How does your development environment look like?
Sentry.init()
Steps to Reproduce
org.gradle.configuration-cache=trueinandroid/gradle.propertiesorg.gradle.configuration-cache.problems=warn(to get past warn-level problems and surface the hard failures)./gradlew :app:bundleRelease(or any release bundle/assemble)Expected Result
The build succeeds with Configuration Cache enabled (stores an entry on the first run, reuses it — and skips the configuration phase — on subsequent runs).
Actual Result
problems=warndoes not rescue these — they are hard execution-time exceptions (this is also what #4252 reported, with warn mode set):The same failure also occurs for
:app:copySentryJsonConfiguration.Root cause
Line references are to
packages/core/sentry.gradle.ktsonmain(shipped in 8.19.0); the Groovysentry.gradlein 8.10.0 has the identical constructs.1.
onlyIfpredicates call closures resolved fromproject's extra properties, and are evaluated at execution time.Also
onlyIf { shouldCopySentryOptionsFile() }at L159 andonlyIf { shouldSentryAutoUploadGeneral() }at L561 (the*_SentryUploadtask).onlyIfruns at execution time; resolving the extra-property closure there is the CC violation.2.
copySentryJsonConfiguration'sdoLasttouchesprojectat execution time.doLast { val appRoot = project.rootDir.parentFile ?: project.rootDir // L106 — project at execution time ... copy { from(sentryOptionsFile); into(androidAssetsDir); ... } // L113 — project.copy at execution time }3.
*_SentryUploadusesproject.loggerat execution time (e.g. L594, L596, and elsewhere in its actions). The CLI invocation itself already uses the CC-safe injectedExecOperations(InjectedExecOps, defined L76, instantiated L577) — so only these residualprojectaccesses remain.Why the usual escape hatches don't work
.ktsrewrite (#6119) does not help — verified by readingsentry.gradle.ktsonmain: it is a syntax migration, the CC-relevant constructs above are unchanged.SENTRY_DISABLE_AUTO_UPLOAD=true,SENTRY_COPY_OPTIONS_FILE=false) does not help:copySentryJsonConfigurationis registered unconditionally (L103) and wired unconditionally viapreBuild.dependsOn("copySentryJsonConfiguration")inafterEvaluate(L781–782), so it is always in the task graph and itsonlyIfis always evaluated. The env var only changes the predicate's result, not whether the failing evaluation runs.Proposed minimal fix (interim, ahead of #796)
All CC-safe patterns, no behaviour change:
onlyIf(L104, L159, L561) — capture the env read at configuration time and reference the captured boolean:(
System.getenvat configuration time is a tracked CC input.)project.rootDir(L106) — capture at configuration time and use the local indoLast.copy {}(L113) — use an injectedFileSystemOperations(same injection pattern already used forExecOperations), orjava.nio.file.Files.copyfor the single-file case.project.logger(L594/L596/actions) — use the task's ownloggerinstead ofproject.logger(the task logger is CC-safe).I'm happy to open a PR with these changes as an interim step before the full SAGP migration in #796 — let me know if you'd prefer to fold it directly into that work instead.
References
react-native/sentry.gradleto SAGP sentry-android-gradle-plugin#796 — Migratereact-native/sentry.gradleto SAGP (open; last roadmap estimate 2025-12-10 has since slipped)sentry.gradle(syntax migration; CC behaviour unchanged)