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

  1. Move @SerializedName from the accessor method to the record component declaration
  2. 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

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


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