{"record":{"id":"10f98fcc595bf3af","repo":"google/gson","slug":"failed-invoking-canaccess","errorCode":null,"errorMessage":"Failed invoking canAccess","messagePattern":"Failed invoking canAccess","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/ReflectionAccessFilterHelper.java","lineNumber":98,"sourceCode":"\n  private abstract static class AccessChecker {\n    static final AccessChecker INSTANCE;\n\n    static {\n      AccessChecker accessChecker = null;\n      // TODO: Ideally should use Multi-Release JAR for this version specific code\n      if (JavaVersion.isJava9OrLater()) {\n        try {\n          Method canAccessMethod =\n              AccessibleObject.class.getDeclaredMethod(\"canAccess\", Object.class);\n          accessChecker =\n              new AccessChecker() {\n                @Override\n                public boolean canAccess(AccessibleObject accessibleObject, Object object) {\n                  try {\n                    return (Boolean) canAccessMethod.invoke(accessibleObject, object);\n                  } catch (Exception e) {\n                    throw new RuntimeException(\"Failed invoking canAccess\", e);\n                  }\n                }\n              };\n        } catch (NoSuchMethodException ignored) {\n          // OK: will assume everything is accessible\n        }\n      }\n\n      if (accessChecker == null) {\n        accessChecker =\n            new AccessChecker() {\n              @Override\n              public boolean canAccess(AccessibleObject accessibleObject, Object object) {\n                // Cannot determine whether object can be accessed, so assume it can be accessed\n                return true;\n              }\n            };\n      }","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/ReflectionAccessFilterHelper.java#L80-L116","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","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."],"exampleFix":"// before\nGson gson = new Gson();\nString json = gson.toJson(objWithInaccessibleFields);\n// after (add-opens at launch)\n//   java --add-opens java.base/java.lang=ALL-UNNAMED -jar app.jar\n// after (filter)\nGsonBuilder b = new GsonBuilder();\nb.addReflectionAccessFilter((c) -> c.getName().startsWith(\"java.\")\n    ? ReflectionAccessFilter.FilterResult.BLOCK_INHERITED_BLOCK_ALL\n    : ReflectionAccessFilter.FilterResult.INDECISIVE);\nGson gson = b.create();","handlingStrategy":"try-catch","validationCode":"// Ensure canAccess can run: add-opens at launch, or filter the type first\nboolean shouldSkip = filterReturnsBlockForType(c);\nif (shouldSkip) throw new SecurityException(\"reflection blocked for \" + c);","typeGuard":"static boolean likelyAccessible(Class<?> c) {\n  return !c.getName().startsWith(\"java.\") || openTo(c);\n}","tryCatchPattern":"try {\n  String json = gson.toJson(obj);\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"Failed invoking canAccess\")) {\n    // module/manager blocked access; fall back to a non-reflective TypeAdapter\n  } else throw e;\n}","preventionTips":["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."],"tags":["gson","reflection","jigsaw","security","jvm"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}