java-native-access/jna · error · java.lang.IllegalArgumentException

fieldName must be a public field of type resultClass.getName

Error message

fieldName must be a public field of type resultClass.getName() (e): mappingClass

What it means

JNA's lookupField helper reads optional public static fields (TYPE_MAPPER, STRUCTURE_ALIGNMENT, STRING_ENCODING) from a library mapping class. If the field exists but cannot be accessed or its value's type does not match the expected resultClass, it throws this IllegalArgumentException naming the field, expected type, and mapping class. A missing field is fine (returns null); a present-but-invalid field is not.

Source

Thrown at src/com/sun/jna/Native.java:883

        libraryOptions = cacheOptions(mappingClass, libraryOptions, null);
        // Store the original lookup class, if different from the mapping class
        if (type != mappingClass) {
            typeOptions.put(type, libraryOptions);
        }
        return libraryOptions;
    }

    private static Object lookupField(Class<?> mappingClass, String fieldName, Class<?> resultClass) {
        try {
            Field field = mappingClass.getField(fieldName);
            field.setAccessible(true);
            return field.get(null);
        }
        catch (NoSuchFieldException e) {
            return null;
        }
        catch (Exception e) {
            throw new IllegalArgumentException(fieldName + " must be a public field of type "
                                               + resultClass.getName() + " ("
                                               + e + "): " + mappingClass);
        }
    }

    /** Return the preferred {@link TypeMapper} for the given native interface.
     * See {@link com.sun.jna.Library#OPTION_TYPE_MAPPER}.
     */
    public static TypeMapper getTypeMapper(Class<?> cls) {
        Map<String, ?> options = getLibraryOptions(cls);
        return (TypeMapper) options.get(Library.OPTION_TYPE_MAPPER);
    }

    /**
     * @param cls The native interface type
     * @return The preferred string encoding for the given native interface.
     * If there is no setting, defaults to the {@link #getDefaultStringEncoding()}.
     * @see com.sun.jna.Library#OPTION_STRING_ENCODING

View on GitHub (pinned to d036ad9781)

Solutions

  1. Correct the field's declared type to match the required type (TypeMapper, Integer, or String respectively) and make it public static
  2. Delete the field if the customization is unnecessary (absence is allowed)
  3. If using a TypeMapper.Provider, ensure it is assignable to the expected type and instantiates cleanly
  4. Check the embedded exception 'e' in the message for the root cause (IllegalAccessException vs ExceptionInInitializerError)

Example fix

// before
public static int STRUCTURE_ALIGNMENT = Structure.ALIGN_DEFAULT;
// after
public static final Integer STRUCTURE_ALIGNMENT = Integer.valueOf(Structure.ALIGN_DEFAULT);
Defensive patterns

Strategy: validation

Validate before calling

static void checkOptionalField(Class<?> c, String name, Class<?> expected) throws Exception {
    try {
        Field f = c.getField(name);
        Object v = f.get(null);
        if (!expected.isInstance(v)) throw new IllegalStateException(name + " must be " + expected.getName());
    } catch (NoSuchFieldException ok) { }
}
// usage: checkOptionalField(MyLib.class, "TYPE_MAPPER", TypeMapper.class);

Type guard

boolean validOptional(Class<?> c, String name, Class<?> expected) {
    try { Field f = c.getField(name); return expected.isInstance(f.get(null)); } catch (Exception e) { return false; }
}

Try / catch

try { Native.load("mylib", MyLib.class); } catch (IllegalArgumentException e) { if (String.valueOf(e.getMessage()).startsWith("TYPE_MAPPER must be")) { throw new IllegalStateException("Check TYPE_MAPPER/STRUCTURE_ALIGNMENT/STRING_ENCODING declarations", e); } throw e; }

Prevention

When it happens

Trigger: Declaring a public static field named TYPE_MAPPER (must be TypeMapper/FieldMapper or TypeMapper.Provider), STRUCTURE_ALIGNMENT (must be Integer), or STRING_ENCODING (must be String) with the wrong type, non-static, or a throwing initializer, then loading the library.

Common situations: Typing TYPE_MAPPER as a concrete class not implementing TypeMapper; making STRUCTURE_ALIGNMENT a raw int instead of Integer; STRING_ENCODING initialized with a non-String; initializer exceptions surfacing as the embedded cause.

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