{"record":{"id":"3ee443b687445e9e","repo":"java-native-access/jna","slug":"this-vm-does-not-support-read-only-fields-field-field","errorCode":null,"errorMessage":"This VM does not support read-only fields (field '\" + field.getName() + \"' within \" + getClass() + \")","messagePattern":"This VM does not support read-only fields \\(field '\" \\+ field\\.getName\\(\\) \\+ \"' within \" \\+ getClass\\(\\) \\+ \"\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/com/sun/jna/Structure.java","lineNumber":1360,"sourceCode":"        LayoutInfo info = new LayoutInfo();\n        info.alignType = this.alignType;\n        info.typeMapper = this.typeMapper;\n\n        boolean firstField = true;\n        for (Iterator<Field> i=fields.iterator();i.hasNext();firstField=false) {\n            Field field = i.next();\n            int modifiers = field.getModifiers();\n\n            Class<?> type = field.getType();\n            if (type.isArray()) {\n                info.variable = true;\n            }\n            StructField structField = new StructField();\n            structField.isVolatile = Modifier.isVolatile(modifiers);\n            structField.isReadOnly = Modifier.isFinal(modifiers);\n            if (structField.isReadOnly) {\n                if (!Platform.RO_FIELDS) {\n                    throw new IllegalArgumentException(\"This VM does not support read-only fields (field '\"\n                                                       + field.getName() + \"' within \" + getClass() + \")\");\n                }\n                // In J2SE VMs, this allows overriding the value of final\n                // fields\n                field.setAccessible(true);\n            }\n            structField.field = field;\n            structField.name = field.getName();\n            structField.type = type;\n\n            // Check for illegal field types\n            if (Callback.class.isAssignableFrom(type) && !type.isInterface()) {\n                throw new IllegalArgumentException(\"Structure Callback field '\"\n                                                   + field.getName()\n                                                   + \"' must be an interface\");\n            }\n            if (type.isArray()\n                && Structure.class.equals(type.getComponentType())) {","sourceCodeStart":1342,"sourceCodeEnd":1378,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/src/com/sun/jna/Structure.java#L1342-L1378","documentation":"JNA must write through Structure fields to synchronize them with native memory. On VMs where final (read-only) fields cannot be set reflectively (Platform.RO_FIELDS == false), a final field inside a Structure is unusable, so IllegalArgumentException is thrown naming the field and Structure class.","triggerScenarios":"Declaring a Structure field as final on a VM/platform whose configuration disallows read-only fields (Platform.RO_FIELDS false), causing StructureFieldInfo/derivation to reject the field.","commonSituations":"Defining public final fields in Structure subclasses by Java habit; running JNA on limited/embedded VMs or security-managed environments where setting accessible final fields is blocked.","solutions":["Remove the final modifier from the Structure field","Make the field non-final and, if immutability is desired, enforce it in application code instead","Upgrade/verify the JNA platform support; on standard J2SE VMs RO_FIELDS is true and final fields are made accessible","Ensure no SecurityManager/restrictions block field.setAccessible(true) for final fields"],"exampleFix":"// before\nclass S extends Structure {\n    public final int count; // read-only field\n}\n// after\nclass S extends Structure {\n    public int count;\n}","handlingStrategy":"type-guard","validationCode":"for (Field f : S.class.getFields()) {\n    if (Modifier.isFinal(f.getModifiers()) && !Platform.RO_FIELDS) {\n        throw new IllegalStateException(\"final field not supported: \" + f);\n    }\n}","typeGuard":"static boolean isWritableField(Field f) {\n    int m = f.getModifiers();\n    return !Modifier.isFinal(m) || Platform.RO_FIELDS;\n}","tryCatchPattern":"try {\n    s.size();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"read-only fields\")) {\n        throw new IllegalStateException(\"Remove final modifier: \" + e.getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Never declare final Structure fields","Check Platform.RO_FIELDS when targeting unusual VMs","Enforce immutability at the application layer, not via final on native-mapped fields","Lint for final fields in Structure subclasses"],"tags":["jna","structure","reflection","final-field","platform"],"backgroundTag":"unsupported-operation","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}