java-native-access/jna · critical · Error

FFI types not initialized

Error message

FFI types not initialized

What it means

Structure's static initializer checks that FFITypes.ffi_type_void (and the other FFI type descriptors) were populated by native code. If the native library was loaded but did not initialize the FFI type table, Structure cannot map Java types to libffi descriptors, so it throws this Error from the static block (surfacing as ExceptionInInitializerError).

Source

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

                || typePointer.equals(FFITypes.ffi_type_sint16)
                || typePointer.equals(FFITypes.ffi_type_uint32)
                || typePointer.equals(FFITypes.ffi_type_sint32)
                || typePointer.equals(FFITypes.ffi_type_uint64)
                || typePointer.equals(FFITypes.ffi_type_sint64)
                || typePointer.equals(FFITypes.ffi_type_pointer);
        }

        private static boolean isFloatType(FFIType type) {
            Pointer typePointer = type.getPointer();
            return typePointer.equals(FFITypes.ffi_type_float)
                || typePointer.equals(FFITypes.ffi_type_double);
        }

        static {
            if (Native.POINTER_SIZE == 0)
                throw new Error("Native library not initialized");
            if (FFITypes.ffi_type_void == null)
                throw new Error("FFI types not initialized");
            ffiTypeInfo.put(FFITypes.ffi_type_void, Structure.newInstance(FFIType.class, FFITypes.ffi_type_void));
            ffiTypeInfo.put(FFITypes.ffi_type_float, Structure.newInstance(FFIType.class, FFITypes.ffi_type_float));
            ffiTypeInfo.put(FFITypes.ffi_type_double, Structure.newInstance(FFIType.class, FFITypes.ffi_type_double));
            ffiTypeInfo.put(FFITypes.ffi_type_longdouble, Structure.newInstance(FFIType.class, FFITypes.ffi_type_longdouble));
            ffiTypeInfo.put(FFITypes.ffi_type_uint8, Structure.newInstance(FFIType.class, FFITypes.ffi_type_uint8));
            ffiTypeInfo.put(FFITypes.ffi_type_sint8, Structure.newInstance(FFIType.class, FFITypes.ffi_type_sint8));
            ffiTypeInfo.put(FFITypes.ffi_type_uint16, Structure.newInstance(FFIType.class, FFITypes.ffi_type_uint16));
            ffiTypeInfo.put(FFITypes.ffi_type_sint16, Structure.newInstance(FFIType.class, FFITypes.ffi_type_sint16));
            ffiTypeInfo.put(FFITypes.ffi_type_uint32, Structure.newInstance(FFIType.class, FFITypes.ffi_type_uint32));
            ffiTypeInfo.put(FFITypes.ffi_type_sint32, Structure.newInstance(FFIType.class, FFITypes.ffi_type_sint32));
            ffiTypeInfo.put(FFITypes.ffi_type_uint64, Structure.newInstance(FFIType.class, FFITypes.ffi_type_uint64));
            ffiTypeInfo.put(FFITypes.ffi_type_sint64, Structure.newInstance(FFIType.class, FFITypes.ffi_type_sint64));
            ffiTypeInfo.put(FFITypes.ffi_type_pointer, Structure.newInstance(FFIType.class, FFITypes.ffi_type_pointer));
            for(FFIType f: ffiTypeInfo.values()) {
                f.read();
            }
            storeTypeInfo(void.class, ffiTypeInfo.get(FFITypes.ffi_type_void));
            storeTypeInfo(Void.class, ffiTypeInfo.get(FFITypes.ffi_type_void));

View on GitHub (pinned to d036ad9781)

Solutions

  1. Remove stale extracted natives from the JNA temp dir (or set -Djna.tmpdir to a fresh location) so the correct jnidispatch is re-extracted
  2. Ensure the jna.jar version and native jnidispatch come from the same build; upgrade both to the latest JNA release together
  3. Do not override native loading with -Djna.nosys or a system-installed libjnidispatch unless it matches the jar's expected ABI
  4. Rebuild jnidispatch from the matching JNA source if using a custom native build
  5. Catch ExceptionInInitializerError on first Structure use and log the JNA version (Native.VERSION) plus native library path to spot the mismatch

Example fix

// before
classpath: jna-5.13.0.jar + manually copied libjnidispatch.so from 5.2.0
// after
classpath: jna-5.13.0.jar only (natives bundled in same artifact, same build)
Defensive patterns

Strategy: try-catch

Validate before calling

boolean ffiReady() {
    try { return com.sun.jna.Native.POINTER_SIZE != 0; }
    catch (Throwable t) { return false; }
}

Try / catch

try {
    new MyStructure();
} catch (ExceptionInInitializerError e) {
    // cause "FFI types not initialized" => jar/native version mismatch
    throw new IllegalStateException("JNA jar/native ABI mismatch; check Native.VERSION=" + com.sun.jna.Native.VERSION, e.getCause());
}

Prevention

When it happens

Trigger: First use of Structure when FFITypes.ffi_type_void is null — i.e. a version/ABI mismatch between the Java jna classes and the loaded jnidispatch native library, or native init partially completed without registering FFI types.

Common situations: Mixing a newer jna.jar with an older jnidispatch binary (or vice versa), manually loading a system libjnidispatch that exports a different ABI, custom builds of JNA where FFI type initialization was skipped, or corrupted native extraction in the temp directory.

Related errors


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