google/gson · error · JsonIOException

memberDescription + " is not accessible and ReflectionAccess

Error message

memberDescription + " is not accessible and ReflectionAccessFilter does not permit making it accessible. Register a TypeAdapter for the declaring type, adjust the access filter or increase the visibility of the element and its declaring type.

What it means

Thrown by checkAccessible() when a ReflectionAccessFilter returned BLOCK_INACCESSIBLE for a type and a specific field, accessor method, or constructor cannot be reached by the calling code without making it accessible. Gson refuses to call setAccessible(true) when the filter forbids it, so serialization or deserialization of that member aborts with a JsonIOException. The error is not about Java module visibility per se, but about the access policy the filter established.

Source

Thrown at gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java:173

      @SuppressWarnings("unchecked")
      TypeAdapter<T> adapter =
          (TypeAdapter<T>)
              new RecordAdapter<>(
                  raw, getBoundFields(gson, type, raw, blockInaccessible, true), blockInaccessible);
      return adapter;
    }

    ObjectConstructor<T> constructor = constructorConstructor.get(type, true);
    return new FieldReflectionAdapter<>(
        constructor, getBoundFields(gson, type, raw, blockInaccessible, false));
  }

  private static <M extends AccessibleObject & Member> void checkAccessible(
      Object object, M member) {
    if (!ReflectionAccessFilterHelper.canAccess(
        member, Modifier.isStatic(member.getModifiers()) ? null : object)) {
      String memberDescription = ReflectionHelper.getAccessibleObjectDescription(member, true);
      throw new JsonIOException(
          memberDescription
              + " is not accessible and ReflectionAccessFilter does not permit making it"
              + " accessible. Register a TypeAdapter for the declaring type, adjust the access"
              + " filter or increase the visibility of the element and its declaring type.");
    }
  }

  private BoundField createBoundField(
      Gson context,
      Field field,
      Method accessor,
      String serializedName,
      TypeToken<?> fieldType,
      boolean serialize,
      boolean blockInaccessible) {

    boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Register a custom TypeAdapter for the declaring type so Gson does not fall back to reflection for it.
  2. Loosen the ReflectionAccessFilter to return ALLOW for that specific type/class, or remove the BLOCK_INACCESSIBLE filter.
  3. Increase visibility of the field (or its class) to public so no setAccessible is required.
  4. Add `opens` directive for the package in module-info.java (JPMS) so reflective deep access is permitted.
  5. For records, ensure the canonical constructor is at least package-accessible and the filter permits it.

Example fix

// before
Gson gson = new GsonBuilder()
    .addReflectionAccessFilter((c) -> FilterResult.BLOCK_INACCESSIBLE)
    .create();
gson.toJson(internalPackageObject); // throws

// after: allow this specific type
.addReflectionAccessFilter((c) ->
    c.getType() == MyType.class ? FilterResult.ALLOW : FilterResult.BLOCK_INACCESSIBLE)
// or register an adapter
.registerTypeAdapter(MyType.class, new MyTypeAdapter())
Defensive patterns

Strategy: validation

Validate before calling

// Before building Gson, verify the filter allows your types
Class<?> target = MyType.class;
FilterResult r = myFilter.apply(new ReflectionAccessFilter.FilterContext(target));
if (r == FilterResult.BLOCK_INACCESSIBLE) {
  Field f = target.getDeclaredField("sensitiveField");
  if (!ReflectionAccessFilterHelper.canAccess(f, null)) {
    throw new IllegalStateException("Will fail: " + f + " is inaccessible under filter");
  }
}

Type guard

null

Try / catch

try {
  gson.toJson(obj);
} catch (JsonIOException e) {
  if (e.getMessage().contains("is not accessible and ReflectionAccessFilter")) {
    // fall back to a manually-registered adapter or skip the field
    log.warn("Access blocked for {}", obj.getClass(), e);
  } else throw e;
}

Prevention

When it happens

Trigger: Occurs when a ReflectionAccessFilter is registered on GsonBuilder (addReflectionAccessFilter) returning FilterResult.BLOCK_INACCESSIBLE, and the target class has private/package-private fields (or an inaccessible record constructor) that Gson then tries to read/write reflectively. Fires from BoundField.write (line 225/229), readIntoField (line 277), or RecordAdapter constructor (line 586).

Common situations: Common on JPMS modular projects where types in another module are not exported; library hardening configs that blanket-block inaccessible members; serializing third-party library classes whose fields are private with no public accessors; mixing records with non-public canonical constructors under a restrictive filter.

Related errors


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/a43c23aab24fd83b.json. Report an issue: GitHub.