{"record":{"id":"d509e4f2322fbffd","repo":"google/gson","slug":"cannot-set-value-of-static-final-fielddescript","errorCode":null,"errorMessage":"Cannot set value of 'static final' ${fieldDescription}","messagePattern":"Cannot set value of 'static final' (.+?)","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/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java#L265-L301","documentation":"During deserialization into a regular (non-record) class, Gson sets each field via Field.set. The JVM prevents setting static final fields even after setAccessible(true), so Gson detects this case explicitly and throws JsonIOException with a clear message instead of letting Field.set fail with a confusing IllegalAccessException.","triggerScenarios":"Deserializing JSON into a class that has a static final field which Gson is not excluding — this only happens when excludeFieldsWithModifiers was configured to remove the default STATIC exclusion.","commonSituations":"A developer calls GsonBuilder.excludeFieldsWithModifiers(Modifier.TRANSIENT) (dropping Modifier.STATIC from the exclusion set), causing Gson to attempt writing to static final constant fields.","solutions":["Ensure STATIC fields remain excluded: excludeFieldsWithModifiers(Modifier.STATIC | Modifier.TRANSIENT) (the default)","Mark the static final field with @Expose(serialize = false, deserialize = false) or transient","Register a custom TypeAdapter for the type to control deserialization without reflection"],"exampleFix":"// before\nGson gson = new GsonBuilder()\n    .excludeFieldsWithModifiers(Modifier.TRANSIENT) // STATIC no longer excluded\n    .create();\ngson.fromJson(\"{\\\"CONST\\\":5}\", Config.class); // throws if Config has 'static final int CONST'\n\n// after\nGson gson = new GsonBuilder()\n    .excludeFieldsWithModifiers(Modifier.STATIC | Modifier.TRANSIENT)\n    .create();","handlingStrategy":"validation","validationCode":"// Verify the Gson configuration does not exclude STATIC fields\nint modifiers = Modifier.STATIC | Modifier.TRANSIENT; // correct default\n// If you must customize, never drop STATIC:\n// .excludeFieldsWithModifiers(Modifier.TRANSIENT) // BAD — re-add Modifier.STATIC","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep Modifier.STATIC in excludeFieldsWithModifiers — it is part of the default for a reason","Audit any call to excludeFieldsWithModifiers to confirm STATIC remains excluded","Mark constant fields transient or @Expose(serialize=false, deserialize=false) as a belt-and-suspenders measure"],"tags":["deserialization","static-final","reflection","configuration"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}