{"record":{"id":"08af6c6ef637b342","repo":"oracle/graal","slug":"bad-argument-kind-at-index-expected-char-got","errorCode":null,"errorMessage":"Bad argument kind at index {}: expected Char, got {}","messagePattern":"Bad argument kind at index (.+?): expected Char, got (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaMethod.java","lineNumber":333,"sourceCode":"            /*\n             * Perform widening primitive conversions (JLS 5.1.2) in order to implement strict\n             * method invocation conversions (JLS 5.3). Also promote to stack kind.\n             */\n            args[i + outputArgumentOffset] = switch (signature.getParameterKind(i)) {\n                case Boolean -> switch (argumentKind) {\n                    case Boolean -> argument.asBoolean() ? 1 : 0;\n                    default ->\n                        throw new IllegalArgumentException(\"Bad argument kind at index \" + i + \": expected Boolean, got \" + argumentKind);\n                };\n                case Byte -> switch (argumentKind) {\n                    case Byte -> argument.asInt();\n                    default ->\n                        throw new IllegalArgumentException(\"Bad argument kind at index \" + i + \": expected Byte, got \" + argumentKind);\n                };\n                case Char -> switch (argumentKind) {\n                    case Char -> argument.asInt();\n                    default ->\n                        throw new IllegalArgumentException(\"Bad argument kind at index \" + i + \": expected Char, got \" + argumentKind);\n                };\n                case Short -> switch (argumentKind) {\n                    case Short, Byte -> argument.asInt();\n                    default ->\n                        throw new IllegalArgumentException(\"Bad argument kind at index \" + i + \": expected Short, got \" + argumentKind);\n                };\n                case Int -> switch (argumentKind) {\n                    case Int, Char, Short, Byte -> argument.asInt();\n                    default ->\n                        throw new IllegalArgumentException(\"Bad argument kind at index \" + i + \": expected Int, got \" + argumentKind);\n                };\n                case Long -> switch (argumentKind) {\n                    case Long, Int, Char, Short, Byte -> argument.asLong();\n                    default ->\n                        throw new IllegalArgumentException(\"Bad argument kind at index \" + i + \": expected Long, got \" + argumentKind);\n                };\n                case Float -> switch (argumentKind) {\n                    case Long, Int, Char, Short, Byte -> (float) argument.asLong();","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaMethod.java#L315-L351","documentation":"Thrown by the argument marshalling switch in EspressoExternalResolvedJavaMethod.invoke when a parameter is declared char but the argument constant's kind is not Char. Char accepts no widening inputs in the adapter (a Char parameter requires a Char constant; only Int/Long/Float/Double parameters accept Char as input), because strict invocation (JLS 5.3) does not widen int to char. Char is also a subword source kind that JVMCI often promotes to Int, making this easy to hit after stack-kind normalization.","triggerScenarios":"Passing JavaConstant.forInt(65) or forShort(...) to a char parameter; constants read from a JVMCI frame or produced by ConstantReflectionProvider.boxAsKind with Int kind.","commonSituations":"Interop layers converting characters to ints; replay/snapshot tooling storing chars as ints; constants that passed through asInt()-based reboxing.","solutions":["Rebox with JavaConstant.forChar((char) c.asInt()) for char parameters","Branch on signature.getParameterKind(i) to preserve Char constants through your pipeline","Fix producers that call JavaConstant.forInt on character data"],"exampleFix":"// before\nargs[i] = JavaConstant.forInt(codePoint); // parameter is char\n\n// after\nargs[i] = JavaConstant.forChar((char) codePoint);","handlingStrategy":"validation","validationCode":"if (signature.getParameterKind(i) == JavaKind.Char && args[i].getJavaKind() != JavaKind.Char) {\n    args[i] = JavaConstant.forChar((char) args[i].asInt());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Char parameters take only Char constants; ints are not implicitly narrowed to char","Character data flowing through int-based APIs must be reboxed with forChar","Beware constants that already passed through asInt() — the kind information is gone"],"tags":["espresso","jvmci","method-invocation","javakind","char","subword"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}