google/gson · error · JsonIOException
Accessor " + accessorDescription + " threw exception
Error message
Accessor " + accessorDescription + " threw exception
What it means
Thrown during serialization of a record when its accessor method (the implicitly or explicitly declared component accessor) throws an exception. Gson catches InvocationTargetException and rethrows a JsonIOException wrapping the original cause (e.getCause()). The failure originates in user code on the record, not in Gson internals.
Source
Thrown at gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java:240
void write(JsonWriter writer, Object source) throws IOException, IllegalAccessException {
if (blockInaccessible) {
if (accessor == null) {
checkAccessible(source, field);
} else {
// Note: This check might actually be redundant because access check for canonical
// constructor should have failed already
checkAccessible(source, accessor);
}
}
Object fieldValue;
if (accessor != null) {
try {
fieldValue = accessor.invoke(source);
} catch (InvocationTargetException e) {
String accessorDescription =
ReflectionHelper.getAccessibleObjectDescription(accessor, false);
throw new JsonIOException(
"Accessor " + accessorDescription + " threw exception", e.getCause());
}
} else {
fieldValue = field.get(source);
}
@SuppressWarnings("ReferenceEquality")
boolean isSameObject = fieldValue == source;
if (isSameObject) {
// avoid direct recursion
return;
}
writer.name(serializedName);
writeTypeAdapter.write(writer, fieldValue);
}
@Override
void readIntoArray(JsonReader reader, int index, Object[] target)View on GitHub (pinned to 8b8628c656)
Solutions
- Inspect the wrapped cause (e.getCause()) in the JsonIOException to find the real failure in the accessor.
- Fix the bug or defensive logic inside the record accessor method.
- Register a JsonSerializer for the record type so Gson does not invoke the accessor.
- Ensure the record instance is in a consistent, fully-initialized state before calling gson.toJson.
Example fix
// before
public record Money(long cents) {
public Money { if (cents < 0) throw new IllegalArgumentException(); }
public long cents() { return Math.toIntExact(cents); } // throws on overflow
}
gson.toJson(new Money(Long.MAX_VALUE));
// after: remove lossy accessor, keep domain check
public long cents() { return cents; } Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
// Guard before serializing a record: invoke its accessors once
static <T> void checkRecordAccessors(T value) throws Throwable {
for (Method m : value.getClass().getMethods()) {
if (m.getParameterCount()==0 && m.getDeclaringClass()==value.getClass()) {
try { m.invoke(value); }
catch (InvocationTargetException e) { throw e.getCause(); }
}
}
} Try / catch
try {
gson.toJson(record);
} catch (JsonIOException e) {
Throwable cause = e.getCause();
// handle the real failure thrown by the accessor
log.error("record accessor failed", cause);
} Prevention
- Keep record accessors pure: no validation that can fail on already-valid state.
- Unit-test record serialization with the full range of values you expect to round-trip.
- Avoid delegating from accessors to services or external state.
- Register a JsonSerializer for records whose accessors are non-trivial.
When it happens
Trigger: A record's accessor method throws because it contains custom logic, is annotated with validation that fails, lazily computes a value that errors, or its state is inconsistent at serialization time. Triggered in BoundField.write (ReflectiveTypeAdapterFactory.java:236) when accessor.invoke(source) raises InvocationTargetException.
Common situations: Records with accessor overrides that delegate to services not initialized at serialization time; records wrapping nullable fields whose accessor does unguarded .get(); records produced by deserialization with null components then re-serialized through a validating accessor; concurrent mutation of a record's components mid-serialize.
Related errors
- @SerializedName on " + methodDescription + " is not supporte
- Deserialization is unsupported
- Deserialization is unsupported
- JSON forbids NaN and infinities: {value}
- memberDescription + " is not accessible and ReflectionAccess
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/ff04c98e1df6ae71.json.
Report an issue: GitHub.