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

  1. 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.
  2. Configure a ReflectionAccessFilter that returns BLOCK for the offending type so Gson never attempts canAccess on it.
  3. Catch the RuntimeException at the deserialization boundary and fall back to a non-reflective TypeAdapter for the affected type.
  4. 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

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


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)