oracle/graal · error · IllegalArgumentException

Bad argument kind at index {}: expected Float, got {}

Error message

Bad argument kind at index {}: expected Float, got {}

What it means

Thrown by the argument marshalling switch in EspressoExternalResolvedJavaMethod.invoke when a parameter is declared float but the argument constant's kind is not in {Long, Int, Char, Short, Byte, Float}. Integral constants are widened and cast to float ((float) asLong()); Double is rejected because double-to-float is a narrowing conversion (JLS 5.1.3) not permitted by strict invocation, and Boolean/Object are invalid. Note the integral path goes through long, which is lossy for large ints converted to float — but that matches JVM widening semantics for byte/char/short/int-to-float via long representation.

Source

Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaMethod.java:354

                    case Short, Byte -> argument.asInt();
                    default ->
                        throw new IllegalArgumentException("Bad argument kind at index " + i + ": expected Short, got " + argumentKind);
                };
                case Int -> switch (argumentKind) {
                    case Int, Char, Short, Byte -> argument.asInt();
                    default ->
                        throw new IllegalArgumentException("Bad argument kind at index " + i + ": expected Int, got " + argumentKind);
                };
                case Long -> switch (argumentKind) {
                    case Long, Int, Char, Short, Byte -> argument.asLong();
                    default ->
                        throw new IllegalArgumentException("Bad argument kind at index " + i + ": expected Long, got " + argumentKind);
                };
                case Float -> switch (argumentKind) {
                    case Long, Int, Char, Short, Byte -> (float) argument.asLong();
                    case Float -> argument.asFloat();
                    default ->
                        throw new IllegalArgumentException("Bad argument kind at index " + i + ": expected Float, got " + argumentKind);
                };
                case Double -> switch (argumentKind) {
                    case Long, Int, Char, Short, Byte -> (double) argument.asLong();
                    case Float -> (double) argument.asFloat();
                    case Double -> argument.asDouble();
                    default ->
                        throw new IllegalArgumentException("Bad argument kind at index " + i + ": expected Double, got " + argumentKind);
                };
                case Object -> {
                    if (argument.isNull()) {
                        yield null;
                    }
                    if (!(argument instanceof EspressoExternalObjectConstant objectConstant)) {
                        throw new IllegalArgumentException(
                                        "Bad argument kind at index " + i + ": expected Object, got " + argumentKind + " wrapped in a " + argument.getClass().getName());
                    }
                    yield objectConstant.getValue();
                }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Narrow explicitly when intended: JavaConstant.forFloat((float) d.asDouble())
  2. For bridges that only produce doubles, insert a kind-conversion step driven by signature.getParameterKind(i)
  3. Confirm the argument index alignment if the kind reported makes no sense for that parameter

Example fix

// before
args[i] = JavaConstant.forDouble(ratio); // parameter is float

// after
args[i] = JavaConstant.forFloat((float) ratio);
Defensive patterns

Strategy: validation

Validate before calling

if (signature.getParameterKind(i) == JavaKind.Float && args[i].getJavaKind() == JavaKind.Double) {
    args[i] = JavaConstant.forFloat((float) args[i].asDouble());
}

Prevention

When it happens

Trigger: Passing JavaConstant.forDouble(...) to a float parameter; passing a Boolean or object constant; constants produced by generic double-based number bridges.

Common situations: Interop from languages with only doubles (JS, Python) where every number is a Double constant; parameter type changed from double to float in a guest class version; misaligned argument arrays.

Related errors


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