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
- Register a custom TypeAdapter for the blocked type via GsonBuilder.registerTypeAdapter(TypeToken, adapter)
- Adjust the ReflectionAccessFilter to return ALLOW or BLOCK_INACCESSIBLE for that specific type instead of BLOCK_ALL
- 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
- Always pair a blocking ReflectionAccessFilter with a registered TypeAdapter for affected types
- Scope filters narrowly (per type) rather than blocking broadly
- Document which types are blocked so callers know to supply adapters
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
- is not accessible and ReflectionAccessFilter does not…
- ReflectionAccessFilter does not permit using reflection for
- Accessor threw exception
- Did not expect a name
- Expected one JSON element but was
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)