java-native-access/jna · error · IllegalArgumentException

Invalid Structure field in " + getClass() + ", field name '"

Error message

Invalid Structure field in " + getClass() + ", field name '" + name + "' (" + type + "): " + e.getMessage()

What it means

JNA validates every field of a Structure subclass by asking the layout engine for its native size. If a field's Java type has no native mapping (unknown class, un-sizeable type), IllegalArgumentException is thrown and re-wrapped with the Structure class, field name and type. It means the structure cannot be laid out in native memory.

Source

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

    private void validateField(String name, Class<?> type) {
        if (typeMapper != null) {
            ToNativeConverter toNative = typeMapper.getToNativeConverter(type);
            if (toNative != null) {
                validateField(name, toNative.nativeType());
                return;
            }
        }
        if (type.isArray()) {
            validateField(name, type.getComponentType());
        }
        else {
            try {
                getNativeSize(type);
            }
            catch(IllegalArgumentException e) {
                String msg = "Invalid Structure field in " + getClass() + ", field name '" + name + "' (" + type + "): " + e.getMessage();
                throw new IllegalArgumentException(msg, e);
            }
        }
    }

    /** ensure all fields are of valid type. */
    private void validateFields() {
        // Try to read the value under the read lock
        cacheStructureLock.readLock().lock();
        try {
            if (validationMap.containsKey(getClass())) {
                return; // Return because this Structure has already been validated
            }
        } finally {
            cacheStructureLock.readLock().unlock();
        }

        // If not found, perform validation and update the cache under the write lock
        cacheStructureLock.writeLock().lock();

View on GitHub (pinned to d036ad9781)

Solutions

  1. Change the field to a JNA-supported type (primitive, wrapper, Pointer, String, WString, Buffer, arrays, nested Structure/Structure.ByReference, Callback)
  2. Register a TypeMapper (or use @Structure.FieldOrder-compatible custom marshalling) covering the custom field type
  3. If the type uses NativeMapped, verify the class implements nativeSize()/toNative()/fromNative() correctly
  4. Read the wrapped cause (e.getMessage) which states which type could not be sized

Example fix

// before
class Cfg extends Structure {
    public MyCustomType cfg; // no native mapping
}
// after
class Cfg extends Structure {
    public Pointer cfg; // or use a TypeMapper/NativeMapped for MyCustomType
}
Defensive patterns

Strategy: type-guard

Validate before calling

for (Field f : Cfg.class.getFields()) {
    Class<?> t = f.getType();
    boolean ok = t.isPrimitive() || Number.class.isAssignableFrom(t) || t == Pointer.class
        || t == String.class || NativeMapped.class.isAssignableFrom(t)
        || Structure.class.isAssignableFrom(t) || t.isArray() || Callback.class.isAssignableFrom(t);
    if (!ok) throw new IllegalStateException("Field not natively mappable: " + f);
}

Type guard

static boolean isMappable(Class<?> t) {
    return t.isPrimitive() || Number.class.isAssignableFrom(t) || t == Pointer.class
        || t == String.class || NativeMapped.class.isAssignableFrom(t)
        || (Structure.class.isAssignableFrom(t) && t != Structure.class)
        || (t.isArray() && t.getComponentType() != Structure.class)
        || (Callback.class.isAssignableFrom(t) && t.isInterface());
}

Try / catch

try {
    cfg.size();
} catch (IllegalArgumentException e) {
    if (e.getCause() != null && e.getMessage().contains("Invalid Structure field")) {
        throw new IllegalStateException("Fix unmapped structure field: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Defining a Structure field whose type has no registered native size: an unknown object type, a type not covered by the TypeMapper or a nested type that fails getNativeSize(type) during field validation (validateFields / calculateSize).

Common situations: Adding a custom class field to a Structure without a TypeMapper; typos in nested structure types; using types only valid after a type mapper is set; version changes where a previously supported type lost its mapping.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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