java-native-access/jna · error · IllegalStateException

Can't parse array content - type not supported

Error message

Can't parse array content - type not supported: <vartype>

What it means

OaIdl.SAFEARRAY's putElement/variant-setting switch only supports specific VARTYPEs (e.g. VT_I4, VT_BSTR, VT_DECIMAL, ...). VT_RECORD and any unrecognized variant type fall into `default` and throw an IllegalStateException naming the vartype.

Solutions

  1. Inspect getVarType() of the SAFEARRAY before writing and handle only supported element types
  2. Unpack VT_RECORD elements manually into supported primitives or a UDT-compliant structure
  3. Wrap the array in a Variant and use Variant.VARIANT-based APIs that support records
  4. Extend/patch the switch in a local fork to support the needed VARTYPE

Example fix

// before
safeArray.putElement(indices, recordValue); // VT_RECORD -> IllegalStateException
// after
if (safeArray.getVarType().intValue() == VAREnum.VT_RECORD) {
    // serialize record fields into supported element types instead
} else {
    safeArray.putElement(indices, recordValue);
}
Defensive patterns

Strategy: type-guard

Validate before calling

int vt = safeArray.getVarType().intValue();
boolean writable = vt != VAREnum.VT_RECORD && SUPPORTED_VARTYPES.contains(vt);

Type guard

boolean isSupportedVartype(int vt) {
    switch (vt) {
        case VAREnum.VT_I2: case VAREnum.VT_I4: case VAREnum.VT_R4:
        case VAREnum.VT_R8: case VAREnum.VT_BSTR: case VAREnum.VT_BOOL:
        case VAREnum.VT_DECIMAL: case VAREnum.VT_UI1: return true;
        default: return false;
    }
}

Try / catch

try {
    safeArray.putElement(indices, value);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("type not supported")) { /* custom write path */ }
    else throw e;
}

Prevention

When it happens

Trigger: Calling SafeArrayPutElement (via SAFEARRAY.putElement or OleAuto) on a SAFEARRAY whose declared varType is VT_RECORD or otherwise unhandled by the switch.

Common situations: Interoperating with COM type libraries that define record-containing safe arrays; arrays created elsewhere (e.g. VB) with record or user-defined types; version differences where newer VT kinds are unsupported.

Related errors


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

Appendix: source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/OaIdl.java:742

                case VT_UNKNOWN:
                    hr = OleAuto.INSTANCE.SafeArrayPutElement(this, paramIndices, ((Unknown) arg).getPointer());
                    COMUtils.checkRC(hr);
                    break;
                case VT_DISPATCH:
                    hr = OleAuto.INSTANCE.SafeArrayPutElement(this, paramIndices, ((Dispatch) arg).getPointer());
                    COMUtils.checkRC(hr);
                    break;
                case VT_CY:
                    hr = OleAuto.INSTANCE.SafeArrayPutElement(this, paramIndices, ((CURRENCY) arg).getPointer());
                    COMUtils.checkRC(hr);
                    break;
                case VT_DECIMAL:
                    hr = OleAuto.INSTANCE.SafeArrayPutElement(this, paramIndices, ((DECIMAL) arg).getPointer());
                    COMUtils.checkRC(hr);
                    break;
                case VT_RECORD:
                default:
                    throw new IllegalStateException("Can't parse array content - type not supported: " + getVarType().intValue());
            }
        }

        /**
         * Retrieve the value at the referenced index from the SAFEARRAY.
         *
         * <p>The function creates a copy of the value. The values are
         * allocated with native functions and need to be freed accordingly.</p>
         *
         * @param indices the index, order follows java/C convention
         * @return the variant
         */
        public Object getElement(int... indices) {
            WinDef.LONG[] paramIndices = new WinDef.LONG[indices.length];
            for (int i = 0; i < indices.length; i++) {
                paramIndices[i] = new WinDef.LONG(indices[indices.length - i - 1]);
            }

View on GitHub (pinned to d036ad9781)