java-native-access/jna · error · IllegalStateException

Can't autogenerate a direct buffer on memory read

Error message

Can't autogenerate a direct buffer on memory read

What it means

Pointer.getValue throws IllegalStateException when reading a Buffer-typed value from memory: JNA cannot materialize a new direct ByteBuffer for the read; it only returns an existing initialized direct Buffer whose backing native pointer matches the memory being read. Autogenerating a buffer during a read is not allowed.

Solutions

  1. Initialize the field with a direct ByteBuffer: ByteBuffer.allocateDirect(n) before reading
  2. Use Pointer.getByteBuffer(offset, size) explicitly instead of getValue with Buffer.class
  3. Ensure the same direct buffer instance is reused and not reallocated between calls
  4. Use Pointer/byte[] types in structures if readback of new memory is needed

Example fix

// before
ByteBuffer buf; // null or heap buffer
Pointer.getValue(offset, ByteBuffer.class, buf);
// after
ByteBuffer buf = ByteBuffer.allocateDirect(64);
pointer.getValue(offset, ByteBuffer.class, buf); // returns same buffer
Defensive patterns

Strategy: validation

Validate before calling

if (buf == null || !buf.isDirect()) {
    buf = ByteBuffer.allocateDirect(size);
}

Type guard

static boolean isDirectBuffer(Object o) {
    return o instanceof Buffer && ((Buffer) o).isDirect();
}

Prevention

When it happens

Trigger: Calling Pointer.getValue(offset, Buffer.class, currentValue) where currentValue is null or a Buffer whose Native.getDirectBufferPointer does not equal the pointer at this offset.

Common situations: Reading a Structure field typed as Buffer that was never initialized with a direct ByteBuffer; passing a heap (non-direct) buffer like ByteBuffer.allocate instead of allocateDirect; buffer's native pointer changed after reallocation.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/com/sun/jna/Pointer.java:428

            if (fp == null) {
                result = null;
            } else {
                Callback cb = (Callback)currentValue;
                Pointer oldfp = CallbackReference.getFunctionPointer(cb);
                if (!fp.equals(oldfp)) {
                    cb = CallbackReference.getCallback(type, fp);
                }
                result = cb;
            }
        } else if (Platform.HAS_BUFFERS && Buffer.class.isAssignableFrom(type)) {
            Pointer bp = getPointer(offset);
            if (bp == null) {
                result = null;
            } else {
                Pointer oldbp = currentValue == null ? null
                    : Native.getDirectBufferPointer((Buffer)currentValue);
                if (oldbp == null || !oldbp.equals(bp)) {
                    throw new IllegalStateException("Can't autogenerate a direct buffer on memory read");
                }
                result = currentValue;
            }
        } else if (NativeMapped.class.isAssignableFrom(type)) {
            NativeMapped nm = (NativeMapped)currentValue;
            if (nm != null) {
                Object value = getValue(offset, nm.nativeType(), null);
                result = nm.fromNative(value, new FromNativeContext(type));
                if (nm.equals(result)) {
                    result = nm;
                }
            } else {
                NativeMappedConverter tc = NativeMappedConverter.getInstance(type);
                Object value = getValue(offset, tc.nativeType(), null);
                result = tc.fromNative(value, new FromNativeContext(type));
            }
        } else if (type.isArray()) {
            result = currentValue;

View on GitHub (pinned to d036ad9781)