java-native-access/jna · error · IllegalArgumentException

setValue must not be called with type set to NULL

Error message

setValue must not be called with type set to NULL

What it means

EVT_VARIANT.setValue() in JNA's Winevt helper wraps an EVT_VARIANT union for the Windows Event Log API. It throws IllegalArgumentException when the caller passes a null EVT_VARIANT_TYPE, because without a type there is no way to know which union field to populate. The null check runs before any switch on the type, so this always fails fast.

Source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/Winevt.java:274

        public boolean isArray() {
            return (Type & EVT_VARIANT_TYPE_ARRAY) == EVT_VARIANT_TYPE_ARRAY;
        }

        public EVT_VARIANT_TYPE getVariantType() {
            return EVT_VARIANT_TYPE.values()[getBaseType()];
        }

        // Helper to store java object for set values
        private Object holder;

        /**
         * @param type
         * @param value
         */
        public void setValue(EVT_VARIANT_TYPE type, Object value) {
            allocateMemory();
            if (type == null) {
                throw new IllegalArgumentException("setValue must not be called with type set to NULL");
            }
            holder = null;
            if (value == null || type == EVT_VARIANT_TYPE.EvtVarTypeNull) {
                Type = EVT_VARIANT_TYPE.EvtVarTypeNull.ordinal();
                Count = 0;
                field1.writeField("pointerValue", Pointer.NULL);
            } else {
                switch (type) {
                    case EvtVarTypeAnsiString:
                        if (value.getClass().isArray() && value.getClass().getComponentType() == String.class) {
                            Type = type.ordinal() | EVT_VARIANT_TYPE_ARRAY;
                            StringArray sa = new StringArray((String[]) value, false);
                            holder = sa;
                            Count = ((String[]) value).length;
                            field1.writeField("pointerValue", sa);
                        } else if (value.getClass() == String.class) {
                            Type = type.ordinal();
                            Memory mem = new Memory(((String) value).length() + 1);

View on GitHub (pinned to d036ad9781)

Solutions

  1. Pass a non-null EVT_VARIANT_TYPE, e.g. EVT_VARIANT_TYPE.EvtVarTypeNull if you intend to clear the variant
  2. If the type comes from a variable or lookup, check for null before calling setValue and substitute EvtVarTypeNull
  3. If clearing the value, call setValue(EVT_VARIANT_TYPE.EvtVarTypeNull, null) instead of passing a null type

Example fix

// before
variant.setValue(null, myValue);
// after
variant.setValue(EVT_VARIANT_TYPE.EvtVarTypeString, myValue);
// or to clear:
variant.setValue(EVT_VARIANT_TYPE.EvtVarTypeNull, null);
Defensive patterns

Strategy: validation

Validate before calling

if (type == null) {
    type = EVT_VARIANT_TYPE.EvtVarTypeNull; // or throw a domain-specific error early
}
variant.setValue(type, value);

Type guard

boolean isValidType(EVT_VARIANT_TYPE t) { return t != null; }

Try / catch

try {
    variant.setValue(type, value);
} catch (IllegalArgumentException e) {
    log.warn("Bad EVT_VARIANT type/value: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling setValue(null, someValue) — e.g. passing an uninitialized or lookup-failed EVT_VARIANT_TYPE variable, or a method returning null type to renderChannelConfig/event-rendering code like testModifyChannelConfig.

Common situations: Mapping an EvtVariant field whose type was read from a struct and turned out null; passing the result of a map lookup (get(typeKey)) that missed; refactoring where the type variable was accidentally not initialized.

Related errors


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