google/gson · error · JsonIOException
Cannot set value of 'static final' " + fieldDescription
Error message
Cannot set value of 'static final' " + fieldDescription
What it means
Thrown during deserialization when Gson attempts to write an incoming JSON value into a field declared `static final`. The JVM forbids reflective Field.set on static final fields (except a few special cases), so Gson detects the modifier combination and throws a JsonIOException before attempting the set. The check happens only when the ReflectionAccessFilter did not block access (otherwise checkAccessible runs first).
Source
Thrown at gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java:283
+ "' of primitive type; at path "
+ reader.getPath());
}
target[index] = fieldValue;
}
@Override
void readIntoField(JsonReader reader, Object target)
throws IOException, IllegalAccessException {
Object fieldValue = typeAdapter.read(reader);
if (fieldValue != null || !isPrimitive) {
if (blockInaccessible) {
checkAccessible(target, field);
} else if (isStaticFinalField) {
// Reflection does not permit setting value of `static final` field, even after calling
// `setAccessible`
// Handle this here to avoid causing IllegalAccessException when calling `Field.set`
String fieldDescription = ReflectionHelper.getAccessibleObjectDescription(field, false);
throw new JsonIOException("Cannot set value of 'static final' " + fieldDescription);
}
field.set(target, fieldValue);
}
}
};
}
private static class FieldsData {
static final FieldsData EMPTY = new FieldsData(Collections.emptyMap(), Collections.emptyList());
/** Maps from JSON member name to field */
final Map<String, BoundField> deserializedFields;
final List<BoundField> serializedFields;
FieldsData(Map<String, BoundField> deserializedFields, List<BoundField> serializedFields) {
this.deserializedFields = deserializedFields;
this.serializedFields = serializedFields;View on GitHub (pinned to 8b8628c656)
Solutions
- Restore the default exclusion by keeping Modifier.STATIC in excludeFieldsWithModifiers, or simply do not customize it.
- Mark the field transient so Gson ignores it.
- Annotate the field with @Expose(serialize=false, deserialize=false) and use excludeFieldsWithoutExposeAnnotation.
- Refactor the constant into an enum or a non-static instance field if you truly need it in JSON.
Example fix
// before
new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.FINAL) // dropped STATIC
.create()
.fromJson(json, Config.class); // throws on `public static final int MAX`
// after: keep default (STATIC | TRANSIENT) or add @ transient
public static transient int max; // or just remove 'static final' Defensive patterns
Strategy: validation
Validate before calling
// Detect static final fields that would be deserialized
for (Field f : Config.class.getDeclaredFields()) {
int m = f.getModifiers();
if (Modifier.isStatic(m) && Modifier.isFinal(m)) {
throw new IllegalStateException("Cannot deserialize into static final " + f);
}
} Type guard
null
Try / catch
try {
gson.fromJson(json, Config.class);
} catch (JsonIOException e) {
if (e.getMessage().startsWith("Cannot set value of 'static final'")) {
// skip / use defaults / fix modifier config
} else throw e;
} Prevention
- Do not remove Modifier.STATIC from excludeFieldsWithModifiers without need.
- Annotate constant fields with @Expose(serialize=false, deserialize=false).
- Mark config constants transient.
- Keep DTOs free of static state entirely.
When it happens
Trigger: Triggered in BoundField.readIntoField (ReflectiveTypeAdapterFactory.java:278) when a deserialized field is static+final and a non-null value is read from JSON. Static fields are excluded by default, but GsonBuilder.excludeFieldsWithModifiers can re-include them; also reachable when fields are not excluded via Excluder.
Common situations: Customizing GsonBuilder.excludeFieldsWithModifiers to drop Modifier.STATIC from the exclusion list; serializing/deserializing classes with constants like `public static final int MAX`; mixing config-holder classes that reuse static finals as JSON keys.
Related errors
- Invalid EnumSet type: {type}
- Invalid EnumMap type: {type}
- Failed to invoke constructor '{constructor}' with no args
- Unable to create instance of {rawType}. Registering an Insta
- Primitive type is not allowed
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/92c721169770b2d3.json.
Report an issue: GitHub.