google/gson · error · RuntimeException
Failed invoking canAccess
Error message
Failed invoking canAccess
What it means
On Java 9+, ReflectionAccessFilterHelper reflects on AccessibleObject.canAccess and invokes it reflectively. If the invocation itself throws (security manager veto, illegal argument, module-access denial), the exception is wrapped and rethrown as RuntimeException('Failed invoking canAccess') (ReflectionAccessFilterHelper.java:98). This indicates the JVM refused the access check, not that the target is inaccessible.
Solutions
- Add Gson to the module path and add-opens the relevant packages, or run with --add-opens java.base/java.lang=ALL-UNNAMED etc., so canAccess can run.
- Configure a ReflectionAccessFilter that returns BLOCK for the offending type so Gson never attempts canAccess on it.
- Catch the RuntimeException at the deserialization boundary and fall back to a non-reflective TypeAdapter for the affected type.
- Upgrade Gson and your JDK; older JDK builds had canAccess bugs.
Example fix
// before
Gson gson = new Gson();
String json = gson.toJson(objWithInaccessibleFields);
// after (add-opens at launch)
// java --add-opens java.base/java.lang=ALL-UNNAMED -jar app.jar
// after (filter)
GsonBuilder b = new GsonBuilder();
b.addReflectionAccessFilter((c) -> c.getName().startsWith("java.")
? ReflectionAccessFilter.FilterResult.BLOCK_INHERITED_BLOCK_ALL
: ReflectionAccessFilter.FilterResult.INDECISIVE);
Gson gson = b.create(); Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure canAccess can run: add-opens at launch, or filter the type first
boolean shouldSkip = filterReturnsBlockForType(c);
if (shouldSkip) throw new SecurityException("reflection blocked for " + c); Type guard
static boolean likelyAccessible(Class<?> c) {
return !c.getName().startsWith("java.") || openTo(c);
} Try / catch
try {
String json = gson.toJson(obj);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("Failed invoking canAccess")) {
// module/manager blocked access; fall back to a non-reflective TypeAdapter
} else throw e;
} Prevention
- Add the necessary --add-opens for your runtime when reflecting on JDK types.
- Register a ReflectionAccessFilter that BLOCKs types you cannot reflect.
- Use explicit TypeAdapters for types that live in locked-down modules.
- Run on a current JDK/Gson combination to avoid known canAccess bugs.
When it happens
Trigger: Gson attempting to determine whether it can reflectively access a field/constructor, on a JVM where AccessibleObject.canAccess(Object) throws (e.g. module system denials, strict SecurityManager, customized JRE, or a null `object` argument where a receiver is required).
Common situations: JPMS modules that deny deep reflection to Gson; running on a minimal/locked-down JRE; passing the wrong `object` (null vs. instance) for an instance member's canAccess; security managers in app servers; JVM bugs or alternative JDKs (Graal, older Android).
Related errors
- Unexpected ReflectiveOperationException occurred
- At most one lower bound is supported
- Exactly one upper bound must be specified
- Failed making accessible; either increase its visibility or…
- is not accessible and ReflectionAccessFilter does not…
AI-assisted analysis of google/gson@310ac341f2 (2026-08-10).
Data as JSON: /api/errors/10f98fcc595bf3af.
Report an issue: GitHub.
Appendix: source
Thrown at gson/src/main/java/com/google/gson/internal/ReflectionAccessFilterHelper.java:98
private abstract static class AccessChecker {
static final AccessChecker INSTANCE;
static {
AccessChecker accessChecker = null;
// TODO: Ideally should use Multi-Release JAR for this version specific code
if (JavaVersion.isJava9OrLater()) {
try {
Method canAccessMethod =
AccessibleObject.class.getDeclaredMethod("canAccess", Object.class);
accessChecker =
new AccessChecker() {
@Override
public boolean canAccess(AccessibleObject accessibleObject, Object object) {
try {
return (Boolean) canAccessMethod.invoke(accessibleObject, object);
} catch (Exception e) {
throw new RuntimeException("Failed invoking canAccess", e);
}
}
};
} catch (NoSuchMethodException ignored) {
// OK: will assume everything is accessible
}
}
if (accessChecker == null) {
accessChecker =
new AccessChecker() {
@Override
public boolean canAccess(AccessibleObject accessibleObject, Object object) {
// Cannot determine whether object can be accessed, so assume it can be accessed
return true;
}
};
}View on GitHub (pinned to 310ac341f2)