{"record":{"id":"210a36f4adcf2683","repo":"java-native-access/jna","slug":"options-must-be-a-public-field-of-type-java-util-map-e","errorCode":null,"errorMessage":"OPTIONS must be a public field of type java.util.Map (e): mappingClass","messagePattern":"OPTIONS must be a public field of type java\\.util\\.Map \\(e\\): mappingClass","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/com/sun/jna/Native.java","lineNumber":852,"sourceCode":"        }\n\n        libraryOptions = typeOptions.get(mappingClass);\n        if (libraryOptions != null) {\n            typeOptions.put(type, libraryOptions);  // cache for next time\n            return libraryOptions;\n        }\n\n        try {\n            Field field = mappingClass.getField(\"OPTIONS\");\n            field.setAccessible(true);\n            libraryOptions = (Map<String, Object>) field.get(null);\n            if (libraryOptions == null) {\n                throw new IllegalStateException(\"Null options field\");\n            }\n        } catch (NoSuchFieldException e) {\n            libraryOptions = Collections.<String, Object>emptyMap();\n        } catch (Exception e) {\n            throw new IllegalArgumentException(\"OPTIONS must be a public field of type java.util.Map (\" + e + \"): \" + mappingClass);\n        }\n        // Make a clone of the original options\n        libraryOptions = new HashMap<>(libraryOptions);\n        if (!libraryOptions.containsKey(Library.OPTION_TYPE_MAPPER)) {\n            libraryOptions.put(Library.OPTION_TYPE_MAPPER, lookupField(mappingClass, \"TYPE_MAPPER\", TypeMapper.class));\n        }\n        if (!libraryOptions.containsKey(Library.OPTION_STRUCTURE_ALIGNMENT)) {\n            libraryOptions.put(Library.OPTION_STRUCTURE_ALIGNMENT, lookupField(mappingClass, \"STRUCTURE_ALIGNMENT\", Integer.class));\n        }\n        if (!libraryOptions.containsKey(Library.OPTION_STRING_ENCODING)) {\n            libraryOptions.put(Library.OPTION_STRING_ENCODING, lookupField(mappingClass, \"STRING_ENCODING\", String.class));\n        }\n        libraryOptions = cacheOptions(mappingClass, libraryOptions, null);\n        // Store the original lookup class, if different from the mapping class\n        if (type != mappingClass) {\n            typeOptions.put(type, libraryOptions);\n        }\n        return libraryOptions;","sourceCodeStart":834,"sourceCodeEnd":870,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/src/com/sun/jna/Native.java#L834-L870","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nprivate static String OPTIONS = \"advanced\";\n// after\npublic static final Map<String, Object> OPTIONS = new HashMap<String, Object>() {{ put(Library.OPTION_CALLING_CONVENTION, Function.C_CONVENTION); }};","handlingStrategy":"validation","validationCode":"static void validateOptions(Class<?> lib) throws Exception {\n    try {\n        Field f = lib.getField(\"OPTIONS\");\n        if (!java.lang.reflect.Modifier.isStatic(f.getModifiers())) throw new IllegalStateException(\"OPTIONS not static\");\n        if (!Map.class.isAssignableFrom(f.getType())) throw new IllegalStateException(\"OPTIONS not a Map\");\n        if (f.get(null) == null) throw new IllegalStateException(\"OPTIONS is null\");\n    } catch (NoSuchFieldException ok) { /* fine: no options */ }\n}","typeGuard":"boolean hasValidOptions(Class<?> c) {\n    try { Field f = c.getField(\"OPTIONS\"); return Map.class.isAssignableFrom(f.getType()) && f.get(null) != null; }\n    catch (Exception e) { return false; }\n}","tryCatchPattern":"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; }","preventionTips":["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"],"tags":["java","reflection","library-options","illegal-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}