java-native-access/jna · error · java.lang.IllegalArgumentException
OPTIONS must be a public field of type java.util.Map (e): ma
Error message
OPTIONS must be a public field of type java.util.Map (e): mappingClass
What it means
When JNA initializes a library mapping it reads the optional static OPTIONS field of the library interface via Class.getField and a cast to Map<String,Object>. If the field exists but is not public/static, not of type Map, is non-null-inaccessible, or throws during access, JNA wraps the failure in this IllegalArgumentException. It means the developer declared an OPTIONS field that does not match the contract documented in Library.
Source
Thrown at src/com/sun/jna/Native.java:852
}
libraryOptions = typeOptions.get(mappingClass);
if (libraryOptions != null) {
typeOptions.put(type, libraryOptions); // cache for next time
return libraryOptions;
}
try {
Field field = mappingClass.getField("OPTIONS");
field.setAccessible(true);
libraryOptions = (Map<String, Object>) field.get(null);
if (libraryOptions == null) {
throw new IllegalStateException("Null options field");
}
} catch (NoSuchFieldException e) {
libraryOptions = Collections.<String, Object>emptyMap();
} catch (Exception e) {
throw new IllegalArgumentException("OPTIONS must be a public field of type java.util.Map (" + e + "): " + mappingClass);
}
// Make a clone of the original options
libraryOptions = new HashMap<>(libraryOptions);
if (!libraryOptions.containsKey(Library.OPTION_TYPE_MAPPER)) {
libraryOptions.put(Library.OPTION_TYPE_MAPPER, lookupField(mappingClass, "TYPE_MAPPER", TypeMapper.class));
}
if (!libraryOptions.containsKey(Library.OPTION_STRUCTURE_ALIGNMENT)) {
libraryOptions.put(Library.OPTION_STRUCTURE_ALIGNMENT, lookupField(mappingClass, "STRUCTURE_ALIGNMENT", Integer.class));
}
if (!libraryOptions.containsKey(Library.OPTION_STRING_ENCODING)) {
libraryOptions.put(Library.OPTION_STRING_ENCODING, lookupField(mappingClass, "STRING_ENCODING", String.class));
}
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;View on GitHub (pinned to d036ad9781)
Solutions
- Change the OPTIONS field to be public static final java.util.Map<String,Object>, e.g. Map OPTIONS = new HashMap();
- If no options are needed, delete the field entirely (JNA treats a missing OPTIONS as empty options)
- Ensure any static initializer populating OPTIONS cannot throw
- Verify the field is not shadowed with a wrong type in a subclass/nested interface
Example fix
// before
private static String OPTIONS = "advanced";
// after
public static final Map<String, Object> OPTIONS = new HashMap<String, Object>() {{ put(Library.OPTION_CALLING_CONVENTION, Function.C_CONVENTION); }}; Defensive patterns
Strategy: validation
Validate before calling
static void validateOptions(Class<?> lib) throws Exception {
try {
Field f = lib.getField("OPTIONS");
if (!java.lang.reflect.Modifier.isStatic(f.getModifiers())) throw new IllegalStateException("OPTIONS not static");
if (!Map.class.isAssignableFrom(f.getType())) throw new IllegalStateException("OPTIONS not a Map");
if (f.get(null) == null) throw new IllegalStateException("OPTIONS is null");
} catch (NoSuchFieldException ok) { /* fine: no options */ }
} Type guard
boolean hasValidOptions(Class<?> c) {
try { Field f = c.getField("OPTIONS"); return Map.class.isAssignableFrom(f.getType()) && f.get(null) != null; }
catch (Exception e) { return false; }
} Try / catch
try { Native.load("mylib", MyLib.class); } catch (IllegalArgumentException e) { if (String.valueOf(e.getMessage()).contains("OPTIONS must be a public field")) { throw new IllegalStateException("Fix MyLib.OPTIONS declaration", e); } throw e; } Prevention
- Always declare OPTIONS as public static final Map<String,Object>
- Never assign null to OPTIONS; omit the field for no options
- Keep static initializers of OPTIONS exception-free
When it happens
Trigger: Calling Native.loadLibrary/Native.load on an interface that declares a static OPTIONS field whose type is not java.util.Map, is not public, is an instance (non-static) field, is initialized to a non-Map value, or whose initializer throws.
Common situations: Typo'd generics or wrong type like public static String OPTIONS; forgetting 'static'; making OPTIONS private/protected; an OPTIONS initializer that throws ExceptionInInitializerError; copy-pasting a CONSTANTS-style field pattern incorrectly.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- fieldName must be a public field of type resultClass.getName
- Component must be heavyweight: " + w
- Class type <paramTypes[i].getName()> not mapped to primitive
- Library must be a proxy class
- FileMonitor not implemented for " + os
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/210a36f4adcf2683.
Report an issue: GitHub.