google/gson · error · JsonIOException

ReflectionAccessFilter does not permit using reflection for

Error message

ReflectionAccessFilter does not permit using reflection for ${raw}. Register a TypeAdapter for this type or adjust the access filter.

What it means

Gson's ReflectiveTypeAdapterFactory uses reflection to serialize/deserialize POJOs. When a registered ReflectionAccessFilter returns FilterResult.BLOCK_ALL for a type (or for a supertype encountered while scanning inherited fields), Gson refuses to use reflection and throws JsonIOException directing you to register a TypeAdapter or adjust the filter. This is a security-hardening feature to prevent reflection on sensitive or restricted types.

Solutions

  1. Register a custom TypeAdapter for the blocked type via GsonBuilder.registerTypeAdapter(TypeToken, adapter)
  2. Adjust the ReflectionAccessFilter to return ALLOW or BLOCK_INACCESSIBLE for that specific type instead of BLOCK_ALL
  3. Exclude the field, or use a different (non-blocked) type for the data

Example fix

// before - filter blocks MyType, toJson throws
gson.toJson(myTypeInstance);

// after - register a TypeAdapter so reflection is not needed
Gson gson = new GsonBuilder()
    .addReflectionAccessFilter(new ReflectionAccessFilter() {
        @Override public FilterResult check(Class<?> raw) {
            return raw == MyType.class ? FilterResult.ALLOW : FilterResult.BLOCK_ALL;
        }
    })
    .registerTypeAdapter(MyType.class, myTypeAdapter)
    .create();
Defensive patterns

Strategy: type-guard

Validate before calling

// Pre-check whether reflection is blocked for a type before serializing
java.util.List<ReflectionAccessFilter> filters = configuredFilters;
FilterResult r = com.google.gson.internal.ReflectionAccessFilterHelper.getFilterResult(filters, MyType.class);
if (r == FilterResult.BLOCK_ALL && !hasCustomAdapter(MyType.class)) {
    throw new IllegalStateException("No adapter and reflection blocked for " + MyType.class);
}

Type guard

// Confirm a TypeAdapter is registered before relying on reflection
static boolean hasAdapter(Gson gson, Class<?> type) {
    return gson.getAdapter(TypeToken.get(type)).getClass().getName().contains("ReflectiveTypeAdapter") == false;
}

Try / catch

try {
  String json = gson.toJson(obj);
} catch (com.google.gson.JsonIOException e) {
  // 'ReflectionAccessFilter does not permit...': register a TypeAdapter or allow the type
}

Prevention

When it happens

Trigger: Registering a ReflectionAccessFilter that blocks a type, then serializing/deserializing an instance of that type without a custom adapter; blocking platform/JDK or third-party library types; JPMS/restricted environments where reflection must be denied by policy.

Common situations: Security hardening that blocks reflection on internal/platform classes; blocking types from untrusted libraries; a global filter that is too broad and catches application types.

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/261b67ef92d8e660. Report an issue: GitHub.

Appendix: source

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

          return null;
        }

        @Override
        public void write(JsonWriter out, T value) throws IOException {
          out.nullValue();
        }

        @Override
        public String toString() {
          return "AnonymousOrNonStaticLocalClassAdapter";
        }
      };
    }

    FilterResult filterResult =
        ReflectionAccessFilterHelper.getFilterResult(reflectionFilters, raw);
    if (filterResult == FilterResult.BLOCK_ALL) {
      throw new JsonIOException(
          "ReflectionAccessFilter does not permit using reflection for "
              + raw
              + ". Register a TypeAdapter for this type or adjust the access filter.");
    }
    boolean blockInaccessible = filterResult == FilterResult.BLOCK_INACCESSIBLE;

    // If the type is actually a Java Record, we need to use the RecordAdapter instead. This will
    // always be false on JVMs that do not support records.
    if (ReflectionHelper.isRecord(raw)) {
      @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);

View on GitHub (pinned to 310ac341f2)