java-native-access/jna · error · IllegalStateException
Null options field
Error message
Null options field
What it means
When initializing a library mapping, JNA reflectively reads the mapping class's public static OPTIONS field and casts it to Map. If the field exists and is accessible but its value is null, JNA throws IllegalStateException('Null options field') because a null options map cannot be defaulted silently on this path.
Solutions
- Initialize OPTIONS with a non-null map, e.g. Collections.emptyMap() if there are no options.
- Remove the OPTIONS field entirely if no options are needed (JNA then uses an empty map).
- Populate OPTIONS in a static initializer before the Native load call runs.
Example fix
// before
public interface MyLib extends Library {
Map<String, Object> OPTIONS = null; // IllegalStateException
}
// after
public interface MyLib extends Library {
Map<String, Object> OPTIONS = Collections.emptyMap();
} Defensive patterns
Strategy: validation
Validate before calling
Object opts = mappingClass.getField("OPTIONS").get(null);
if (opts == null) {
throw new IllegalStateException("OPTIONS must be initialized (use Collections.emptyMap(), not null)");
} Type guard
boolean hasNonNullOptions(Class<?> c) throws Exception {
try {
return c.getField("OPTIONS").get(null) != null;
} catch (NoSuchFieldException e) {
return true; // absence is fine, JNA defaults to empty map
}
} Try / catch
try {
lib = Native.load(name, mappingClass, options);
} catch (IllegalStateException e) {
if ("Null options field".equals(e.getMessage())) {
// fix mapping: initialize OPTIONS
}
throw e;
} Prevention
- Initialize OPTIONS to Collections.emptyMap() rather than leaving it null.
- Delete unused OPTIONS fields so JNA applies its empty-map default.
- Never assign null to OPTIONS, even temporarily, in a static initializer.
When it happens
Trigger: Declaring 'public static Map<String, Object> OPTIONS;' (or assigning null) in a Library interface and letting Native read it during library setup — field is found via getField("OPTIONS") but its value is null.
Common situations: Copy-pasted OPTIONS declaration never initialized; refactoring that replaced the map with null; conditional initialization that didn't run before class load; OPTIONS = null left behind after removing options.
Related errors
- Interface ( ) of library= does not extend Library
- OPTIONS must be a public field of type java.util.Map
- Allocation size must be greater than zero
- Area is not polygonal: " + area
- Argument value 0x exceeds native capacity ( bytes) mask=0x
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/7449b4b2ed8bbbe4.
Report an issue: GitHub.
Appendix: source
Thrown at src/com/sun/jna/Native.java:847
Class<?> mappingClass = findEnclosingLibraryClass(type);
if (mappingClass != null) {
loadLibraryInstance(mappingClass);
} else {
mappingClass = type;
}
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);View on GitHub (pinned to d036ad9781)