{"id":"92c721169770b2d3","repo":"google/gson","slug":"cannot-set-value-of-static-final-fielddescri","errorCode":null,"errorMessage":"Cannot set value of 'static final' \" + fieldDescription","messagePattern":"Cannot set value of 'static final' \" \\+ fieldDescription","errorType":"exception","errorClass":"JsonIOException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java","lineNumber":283,"sourceCode":"                  + \"' of primitive type; at path \"\n                  + reader.getPath());\n        }\n        target[index] = fieldValue;\n      }\n\n      @Override\n      void readIntoField(JsonReader reader, Object target)\n          throws IOException, IllegalAccessException {\n        Object fieldValue = typeAdapter.read(reader);\n        if (fieldValue != null || !isPrimitive) {\n          if (blockInaccessible) {\n            checkAccessible(target, field);\n          } else if (isStaticFinalField) {\n            // Reflection does not permit setting value of `static final` field, even after calling\n            // `setAccessible`\n            // Handle this here to avoid causing IllegalAccessException when calling `Field.set`\n            String fieldDescription = ReflectionHelper.getAccessibleObjectDescription(field, false);\n            throw new JsonIOException(\"Cannot set value of 'static final' \" + fieldDescription);\n          }\n          field.set(target, fieldValue);\n        }\n      }\n    };\n  }\n\n  private static class FieldsData {\n    static final FieldsData EMPTY = new FieldsData(Collections.emptyMap(), Collections.emptyList());\n\n    /** Maps from JSON member name to field */\n    final Map<String, BoundField> deserializedFields;\n\n    final List<BoundField> serializedFields;\n\n    FieldsData(Map<String, BoundField> deserializedFields, List<BoundField> serializedFields) {\n      this.deserializedFields = deserializedFields;\n      this.serializedFields = serializedFields;","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java#L265-L301","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnew GsonBuilder()\n    .excludeFieldsWithModifiers(Modifier.FINAL) // dropped STATIC\n    .create()\n    .fromJson(json, Config.class); // throws on `public static final int MAX`\n\n// after: keep default (STATIC | TRANSIENT) or add @ transient\npublic static transient int max; // or just remove 'static final'","handlingStrategy":"validation","validationCode":"// Detect static final fields that would be deserialized\nfor (Field f : Config.class.getDeclaredFields()) {\n  int m = f.getModifiers();\n  if (Modifier.isStatic(m) && Modifier.isFinal(m)) {\n    throw new IllegalStateException(\"Cannot deserialize into static final \" + f);\n  }\n}","typeGuard":"null","tryCatchPattern":"try {\n  gson.fromJson(json, Config.class);\n} catch (JsonIOException e) {\n  if (e.getMessage().startsWith(\"Cannot set value of 'static final'\")) {\n    // skip / use defaults / fix modifier config\n  } else throw e;\n}","preventionTips":["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."],"tags":["gson","deserialization","static-final","reflection","modifiers"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}