java-native-access/jna · error · IllegalArgumentException

Structure " + getClass() + " has unknown or zero size…

Error message

Structure " + getClass() + " has unknown or zero size (ensure all fields are public)"

What it means

After field calculation, the Structure ended up with size zero or unknown — normally because no fields were included in the layout (e.g. all fields non-public, since JNA only lays out public fields) or the structure genuinely has no sizeable fields. IllegalArgumentException names the Structure class.

Solutions

  1. Declare all native-mapped fields public (JNA skips non-public fields)
  2. Check that the Structure actually has at least one instance field of a supported type
  3. If fields exist but are skipped, remove static/transient modifiers or make them public
  4. Verify field ordering setup (FieldOrder annotation or getFieldOrder override) includes all fields

Example fix

// before
class S extends Structure {
    private int x; // skipped: not public
}
// after
class S extends Structure {
    public int x;
}
Defensive patterns

Strategy: validation

Validate before calling

int publicInstanceFields = 0;
for (Field f : S.class.getDeclaredFields()) {
    int m = f.getModifiers();
    if (Modifier.isPublic(m) && !Modifier.isStatic(m) && !Modifier.isTransient(m)) publicInstanceFields++;
}
if (publicInstanceFields == 0) throw new IllegalStateException("No public fields in " + S.class);

Type guard

static boolean hasLayableFields(Class<?> c) {
    for (Field f : c.getFields()) {
        int m = f.getModifiers();
        if (Modifier.isPublic(m) && !Modifier.isStatic(m) && !Modifier.isTransient(m)) return true;
    }
    return false;
}

Try / catch

try {
    s.size();
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("unknown or zero size")) {
        throw new IllegalStateException("Add public native-mapped fields to " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Structure subclass with zero fields, all fields private/protected (skipped by the fieldInfo loop's Modifier.isPublic check), or all fields deferred as null arrays while forcing size; calling size()/write()/read() on such a structure.

Common situations: Making fields private and exposing getters (JavaBean style); forgetting @Structure.FieldOrder/field list entirely on an empty subclass; nested structure with only static or transient members.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

                structField.offset = calculatedSize;
                calculatedSize += structField.size;
            }

            // Save the field in our list
            info.fields.put(structField.name, structField);
        }

        if (calculatedSize > 0) {
            int size = addPadding(calculatedSize, info.alignment);
            // Update native FFI type information, if needed
            if (this instanceof ByValue && !avoidFFIType) {
                getTypeInfo();
            }
            info.size = size;
            return info;
        }

        throw new IllegalArgumentException("Structure " + getClass()
                                           + " has unknown or zero size (ensure "
                                           + "all fields are public)");
    }

    /**
     * Initialize any null-valued fields that should have a non-null default
     * value.
     */
    @SuppressWarnings("UseSpecificCatch")
    private void initializeFields() {
        // Get the full field list, don't care about sorting
        List<Field> flist = getFieldList();
        for (Field f : flist) {
            try {
                Object o = f.get(this);
                if (o == null) {
                    initializeField(f, f.getType());
                }

View on GitHub (pinned to d036ad9781)