oracle/graal · error · IllegalArgumentException

For static fields, the receiver argument must be null

Error message

For static fields, the receiver argument must be null

What it means

Thrown by HostVMAccess.writeField when writing a static field with a non-null receiver constant. Static field access needs no object, so passing a receiver is a caller contract violation, mirroring the equivalent rule in invoke for static methods.

Source

Thrown at compiler/src/jdk.graal.compiler.hostvmaccess/src/jdk/graal/compiler/hostvmaccess/HostVMAccess.java:227

            if (cause instanceof HostProxyExceptionImpl) {
                throw new InvocationException(cause.getCause());
            }
            throw new InvocationException(snippetReflection.forObject(cause), cause);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Should not reach here", e);
        }
    }

    @Override
    public void writeField(ResolvedJavaField field, JavaConstant receiver, JavaConstant value) {
        SnippetReflectionProvider snippetReflection = providers.getSnippetReflection();
        Field reflectionField = snippetReflection.originalField(field);
        makeAccessible(reflectionField);
        var fieldKind = field.getJavaKind();

        if (Modifier.isStatic(reflectionField.getModifiers())) {
            if (receiver != null) {
                throw new IllegalArgumentException("For static fields, the receiver argument must be null");
            }
        } else if (receiver == null) {
            throw new NullPointerException("For instance fields, the receiver argument must not be null");
        } else if (receiver.isNull()) {
            throw new IllegalArgumentException("For instance fields, the receiver argument must not represent a null constant");
        }

        Object unboxedValue;
        if (fieldKind.isObject()) {
            unboxedValue = snippetReflection.asObject(reflectionField.getType(), value);
        } else {
            assert fieldKind.isPrimitive();
            if (fieldKind != value.getJavaKind()) {
                throw new IllegalArgumentException("Expected value kind " + fieldKind + " but got " + value.getJavaKind());
            }
            unboxedValue = value.asBoxedPrimitive();
        }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Pass null as receiver for static fields
  2. Branch on Modifier.isStatic(reflectionField.getModifiers()) — or field.isStatic() on the ResolvedJavaField — before building the receiver, exactly as the guard does

Example fix

// before
hostVM.writeField(staticField, snippetReflection.forObject(holder), value);  // throws

// after
JavaConstant receiver = field.isStatic() ? null : snippetReflection.forObject(holder);
hostVM.writeField(staticField, receiver, value);
Defensive patterns

Strategy: validation

Validate before calling

if (field.isStatic() && receiver != null) {
    throw new IllegalArgumentException("receiver must be null for static field " + field);

Type guard

static boolean needsReceiver(ResolvedJavaField f) { return !f.isStatic(); }

Try / catch

catch (IllegalArgumentException e) { drop the receiver for static fields and re-invoke }

Prevention

When it happens

Trigger: Calling writeField(staticField, receiver, value) with any non-null JavaConstant as receiver, where reflectionField has the static modifier.

Common situations: Shared field-writing helper that always computes a receiver (forObject(holder)) regardless of staticness; refactor turning an instance field static without updating call sites.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/5944a0e707858723. Report an issue: GitHub.