java-native-access/jna · error · UnsupportedOperationException

Attempt to write to read-only field '" + field.getName() + "

Error message

Attempt to write to read-only field '" + field.getName() + "' within " + getClass()

What it means

Structure.setFieldValue catches IllegalAccessException while writing a field; if the field is final and override is not requested, JNA throws UnsupportedOperationException stating the field is read-only. It prevents silently writing to fields the developer declared immutable.

Source

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

     */
    void setFieldValue(Field field, Object value) {
        setFieldValue(field, value, false);
    }

    private void setFieldValue(Field field, Object value, boolean overrideFinal) {

        try {
            field.set(this, value);
        }
        catch(IllegalAccessException e) {
            int modifiers = field.getModifiers();
            if (Modifier.isFinal(modifiers)) {
                if (overrideFinal) {
                    // WARNING: setAccessible(true) on J2ME does *not* allow
                    // overwriting of a final field.
                    throw new UnsupportedOperationException("This VM does not support Structures with final fields (field '" + field.getName() + "' within " + getClass() + ")", e);
                }
                throw new UnsupportedOperationException("Attempt to write to read-only field '" + field.getName() + "' within " + getClass(), e);
            }
            throw new Error("Unexpectedly unable to write to field '" + field.getName() + "' within " + getClass(), e);
        }
    }

    /** Only keep the original structure if its native address is unchanged.
     * Otherwise replace it with a new object.
     * @param type Structure subclass
     * @param s Original Structure object
     * @param address the native <code>struct *</code>
     * @return Updated <code>Structure.ByReference</code> object
     */
    static <T extends Structure> T updateStructureByReference(Class<T> type, T s, Pointer address) {
        if (address == null) {
            s = null;
        }
        else {
            if (s == null || !address.equals(s.getPointer())) {

View on GitHub (pinned to d036ad9781)

Solutions

  1. Remove the final modifier so the field can be written to native memory and back
  2. Do not call writeField on fields intended to be immutable; compute them as derived values instead
  3. Make the field static final if it is a true constant (static fields are not part of the layout)
  4. Set a different design: keep a mutable private field and expose an unmodifiable getter

Example fix

// before
public final int flags;
...
struct.writeField("flags", 7);
// after
public int flags;
...
struct.writeField("flags", 7);
Defensive patterns

Strategy: type-guard

Validate before calling

if (java.lang.reflect.Modifier.isFinal(struct.getClass().getField(name).getModifiers())) {
    throw new IllegalArgumentException("Cannot write final structure field: " + name);
}

Type guard

if (java.lang.reflect.Modifier.isFinal(field.getModifiers())) return false; // skip write

Try / catch

try { struct.writeField(name, value); } catch (UnsupportedOperationException e) { /* read-only field: ignore or fail */ }

Prevention

When it happens

Trigger: Calling writeField(name, value) or setFieldValue on a final instance field of a Structure without the internal final-override path enabled; read() attempting to refresh a final field when the VM disallows the override.

Common situations: Declaring fields final expecting them to be populated once by a constructor, then trying to update them via writeField; migrating code from mutable to final fields and keeping JNA write calls.

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/c6719941b169b498. Report an issue: GitHub.