google/gson · error · JsonIOException
@SerializedName on ${methodDescription} is not supported
Error message
@SerializedName on ${methodDescription} is not supported What it means
For records, Gson resolves the JSON name from the record component/field, never from the accessor method. If it detects @SerializedName on the accessor method while the underlying field lacks it, it throws JsonIOException during adapter construction because the annotation would be silently ignored.
Source
Thrown at gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java:383
// GsonBuilder.excludeFieldsWithModifiers can overwrite this.
if (Modifier.isStatic(field.getModifiers())) {
deserialize = false;
} else {
accessor = ReflectionHelper.getAccessor(raw, field);
// If blockInaccessible, skip and perform access check later
if (!blockInaccessible) {
ReflectionHelper.makeAccessible(accessor);
}
// @SerializedName can be placed on accessor method, but it is not supported there
// If field and method have annotation it is not easily possible to determine if
// accessor method is implicit and has inherited annotation, or if it is explicitly
// declared with custom annotation
if (accessor.getAnnotation(SerializedName.class) != null
&& field.getAnnotation(SerializedName.class) == null) {
String methodDescription =
ReflectionHelper.getAccessibleObjectDescription(accessor, false);
throw new JsonIOException(
"@SerializedName on " + methodDescription + " is not supported");
}
}
}
// If blockInaccessible, skip and perform access check later
// For Records if the accessor method is used the field does not have to be made accessible
if (!blockInaccessible && accessor == null) {
ReflectionHelper.makeAccessible(field);
}
Type fieldType = GsonTypes.resolve(type.getType(), raw, field.getGenericType());
List<String> fieldNames = getFieldNames(field);
String serializedName = fieldNames.get(0);
BoundField boundField =
createBoundField(
context,
field,View on GitHub (pinned to 310ac341f2)
Solutions
- Move @SerializedName from the accessor method to the record component declaration
- Remove the @SerializedName from the accessor method and use the component-level annotation or default naming
Example fix
// before
record Item(int id) {
@SerializedName("identifier")
@Override public int id() { return id; } // throws
}
// after
record Item(@SerializedName("identifier") int id) {} Defensive patterns
Strategy: validation
Validate before calling
// At startup, validate that no record accessor carries @SerializedName
for (Method m : recordType.getDeclaredMethods()) {
if (m.isAnnotationPresent(SerializedName.class)) {
throw new IllegalStateException("@SerializedName must be on the record component, not accessor: " + m);
}
} Prevention
- Place @SerializedName on the record component, never on the accessor method
- Build Gson at startup to catch this error immediately
- Review IDE-generated accessor methods for stray annotations
When it happens
Trigger: Explicitly declaring a record accessor method and annotating it with @SerializedName, e.g. record Item(int id){ @SerializedName("x") @Override public int id(){...} }.
Common situations: Migrating a class with annotated getters to a record; IDE auto-generating accessor methods that carry annotations; misunderstanding where Gson reads record annotations.
Related errors
- Invalid attempt to bind an instance of ${className} as a @Js
- types and labels must be unique
- Only combinations of \n and \r are allowed in newline.
- Only combinations of spaces and tabs are allowed in indent.
- GSON (${GsonBuildConfig.VERSION}) cannot handle ${type}
AI-assisted analysis of google/gson@310ac341f2 (2026-08-10).
Data as JSON: /api/errors/962bf65f489279c8.
Report an issue: GitHub.