java-native-access/jna · error · IllegalArgumentException
Structures require bidirectional type conversion for " + typ
Error message
Structures require bidirectional type conversion for " + type
What it means
When a TypeMapper supplies only a one-way converter (toNative or fromNative) but not both, JNA cannot round-trip the field value between Java and native memory. Structures need bidirectional conversion, so IllegalArgumentException is thrown naming the type.
Source
Thrown at src/com/sun/jna/Structure.java:1419
nativeType = tc.nativeType();
structField.writeConverter = tc;
structField.readConverter = tc;
structField.context = new StructureReadContext(this, field);
}
else if (typeMapper != null) {
ToNativeConverter writeConverter = typeMapper.getToNativeConverter(type);
FromNativeConverter readConverter = typeMapper.getFromNativeConverter(type);
if (writeConverter != null && readConverter != null) {
value = writeConverter.toNative(value,
new StructureWriteContext(this, structField.field));
nativeType = value != null ? value.getClass() : Pointer.class;
structField.writeConverter = writeConverter;
structField.readConverter = readConverter;
structField.context = new StructureReadContext(this, field);
}
else if (writeConverter != null || readConverter != null) {
String msg = "Structures require bidirectional type conversion for " + type;
throw new IllegalArgumentException(msg);
}
}
if (value == null) {
value = initializeField(structField.field, type);
}
try {
structField.size = getNativeSize(nativeType, value);
fieldAlignment = getNativeAlignment(nativeType, value, firstField);
}
catch(IllegalArgumentException e) {
// Might simply not yet have a type mapper set yet
if (!force && typeMapper == null) {
return null;
}
String msg = "Invalid Structure field in " + getClass() + ", field name '" + structField.name + "' (" + structField.type + "): " + e.getMessage();
throw new IllegalArgumentException(msg, e);View on GitHub (pinned to d036ad9781)
Solutions
- Implement a TypeMapper whose getToNativeConverter and getFromNativeConverter both return converters for the field type
- If the field is genuinely read-only in native terms, use a Pointer or raw type and read manually instead of a one-way mapper
- Verify the mapper's registry includes the exact Java type (and its subclasses) on both sides
Example fix
// before
mapper.getToNativeConverter(...); // only toNative registered
// after
class MyMapper implements TypeMapper {
public ToNativeConverter getToNativeConverter(Class<?> c) { ... }
public FromNativeConverter getFromNativeConverter(Class<?> c) { ... } // both directions
} Defensive patterns
Strategy: validation
Validate before calling
TypeMapper m = ...;
for (Class<?> t : mappedFieldTypes) {
if (m.getToNativeConverter(t) == null || m.getFromNativeConverter(t) == null) {
throw new IllegalStateException("Converter not bidirectional for " + t);
}
} Try / catch
try {
s.size();
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("bidirectional")) {
throw new IllegalStateException("Register both to/from converters for " + e.getMessage(), e);
}
throw e;
} Prevention
- Always implement both converter directions in a TypeMapper
- Test mappers by round-tripping each mapped type
- Reuse existing mappers known to be bidirectional
- Document single-direction mappers as unsuitable for Structures
When it happens
Trigger: Setting a TypeMapper whose FromNativeConverter or ToNativeConverter covers a type but not the reverse direction, then calculating layout/writing a Structure field of that type.
Common situations: Custom mappers written for serialization only (toNative) and reused for structures; combining multiple mappers where one side's registry misses a type; third-party TypeMapper implementations that only implement one converter interface.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Invalid Structure field in " + getClass() + ", field name '"
- Function <name> declared Structure[] at parameter <index> bu
- Function <name> declared Structure[] at parameter <index> bu
- Structure array must have non-zero length
- Need an initialized array
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/af7baa22b0c55346.
Report an issue: GitHub.