java-native-access/jna · error · IllegalArgumentException

This VM does not support read-only fields (field '" + field.

Error message

This VM does not support read-only fields (field '" + field.getName() + "' within " + getClass() + ")

What it means

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.

Source

Thrown at src/com/sun/jna/Structure.java:1360

        LayoutInfo info = new LayoutInfo();
        info.alignType = this.alignType;
        info.typeMapper = this.typeMapper;

        boolean firstField = true;
        for (Iterator<Field> i=fields.iterator();i.hasNext();firstField=false) {
            Field field = i.next();
            int modifiers = field.getModifiers();

            Class<?> type = field.getType();
            if (type.isArray()) {
                info.variable = true;
            }
            StructField structField = new StructField();
            structField.isVolatile = Modifier.isVolatile(modifiers);
            structField.isReadOnly = Modifier.isFinal(modifiers);
            if (structField.isReadOnly) {
                if (!Platform.RO_FIELDS) {
                    throw new IllegalArgumentException("This VM does not support read-only fields (field '"
                                                       + field.getName() + "' within " + getClass() + ")");
                }
                // In J2SE VMs, this allows overriding the value of final
                // fields
                field.setAccessible(true);
            }
            structField.field = field;
            structField.name = field.getName();
            structField.type = type;

            // Check for illegal field types
            if (Callback.class.isAssignableFrom(type) && !type.isInterface()) {
                throw new IllegalArgumentException("Structure Callback field '"
                                                   + field.getName()
                                                   + "' must be an interface");
            }
            if (type.isArray()
                && Structure.class.equals(type.getComponentType())) {

View on GitHub (pinned to d036ad9781)

Solutions

  1. Remove the final modifier from the Structure field
  2. Make the field non-final and, if immutability is desired, enforce it in application code instead
  3. Upgrade/verify the JNA platform support; on standard J2SE VMs RO_FIELDS is true and final fields are made accessible
  4. Ensure no SecurityManager/restrictions block field.setAccessible(true) for final fields

Example fix

// before
class S extends Structure {
    public final int count; // read-only field
}
// after
class S extends Structure {
    public int count;
}
Defensive patterns

Strategy: type-guard

Validate before calling

for (Field f : S.class.getFields()) {
    if (Modifier.isFinal(f.getModifiers()) && !Platform.RO_FIELDS) {
        throw new IllegalStateException("final field not supported: " + f);
    }
}

Type guard

static boolean isWritableField(Field f) {
    int m = f.getModifiers();
    return !Modifier.isFinal(m) || Platform.RO_FIELDS;
}

Try / catch

try {
    s.size();
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("read-only fields")) {
        throw new IllegalStateException("Remove final modifier: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/3ee443b687445e9e. Report an issue: GitHub.