Gradle Test "does not open ... to unnamed module" - Fix --add-opens in CI
A Gradle test task fails on JDK 17+ because a test (or a library it uses) reflects into an encapsulated JDK package and the forked test JVM was not granted --add-opens. Strong encapsulation turns what was a warning on JDK 8/11 into a hard InaccessibleObjectException.
What this error means
The test task fails with Unable to make ... accessible: module java.base does not "opens java.lang" to unnamed module. The forked test JVM needs explicit --add-opens, which is not set in the Test task config.
> Task :app:test FAILED
java.lang.reflect.InaccessibleObjectException: Unable to make field
java.lang.String.value accessible: module java.base does not "opens java.lang"
to unnamed module @4e0e2f2aDiagnose it: get the real failure out of Gradle
Gradle summarises failures aggressively, and the top-level message frequently describes a downstream symptom rather than the cause. Re-run the failing task with diagnostics before changing build logic.
# the actual stack, plus what Gradle decided about the build
./gradlew <task> --stacktrace --info
# is a stale daemon or cache involved?
./gradlew --stop
./gradlew <task> --no-daemon --no-build-cache
# what does Gradle think the environment is?
./gradlew -versionCommon causes
Deep reflection in tests on an encapsulated package
A serialization/mock/proxy library used in tests reflects into java.base internals, which JDK 17 blocks unless the package is opened to the test JVM.
Test task not granted the needed --add-opens
The fix is per-JVM flags on the forked test JVM. Without jvmArgs("--add-opens ...") the test process denies the reflective access.
How to fix it
Add --add-opens to the Test task jvmArgs
Open the package(s) the tests reflect on to the forked test JVM.
tasks.test {
jvmArgs(
"--add-opens", "java.base/java.lang=ALL-UNNAMED",
"--add-opens", "java.base/java.util=ALL-UNNAMED"
)
}Prefer upgrading the offending library
If a dependency forces deep reflection, a newer JDK-17-compatible version often removes the need for --add-opens.
./gradlew :app:dependencies --configuration testRuntimeClasspath
# identify the library doing deep reflection and bump itConfiguration cache and CI
- The configuration cache rejects build logic that reads mutable state at execution time, which is why enabling it surfaces errors an existing build never showed.
- Run with
--configuration-cache-problems=warnfirst to see the full list rather than failing on the first one. - A cached configuration keyed to a different environment is worse than none. Include the JDK version in your cache key.
How to prevent it
- Add the required
--add-opensto the Test taskjvmArgs. - Upgrade test/runtime libraries to JDK-17-compatible versions where possible.
- Run tests on the target JDK so encapsulation errors surface early.