oracle/graal · error · IllegalArgumentException

unknown primitive or void type character:

Error message

unknown primitive or void type character: 

What it means

JavaKind.fromPrimitiveOrVoidTypeChar maps a single JVM type descriptor character to a JavaKind: Z,C,F,D,B,S,I,J,V. Any other character (including 'L' for references or '[' for arrays, which this method intentionally does not handle) yields IllegalArgumentException 'unknown primitive or void type character'.

Source

Thrown at espresso-shared/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaKind.java:261

    public static JavaKind fromWordSize(int wordSizeInBytes) {
        if (wordSizeInBytes == 8) {
            return JavaKind.Long;
        } else {
            assert wordSizeInBytes == 4 : "Unsupported word size!";
            return JavaKind.Int;
        }
    }

    /**
     * Returns the kind from the character describing a primitive or void. An exception is thrown if
     * the character doesn't correspond to any primitive or void type.
     *
     * @param ch the character for a void or primitive kind as returned by {@link #getTypeChar()}
     */
    public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) {
        JavaKind kind = fromPrimitiveOrVoidTypeCharOrNull(ch);
        if (kind == null) {
            throw new IllegalArgumentException(invalidTypeCharMessage(ch));
        }
        return kind;
    }

    /**
     * Returns the kind from the character describing a primitive or void. If the character doesn't
     * correspond to any primitive or void type, null is returned.
     *
     * @param ch the character for a void or primitive kind as returned by {@link #getTypeChar()}
     */
    public static JavaKind fromPrimitiveOrVoidTypeCharOrNull(char ch) {
        return switch (ch) {
            case 'Z' -> Boolean;
            case 'C' -> Char;
            case 'F' -> Float;
            case 'D' -> Double;
            case 'B' -> Byte;
            case 'S' -> Short;

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Filter reference/array descriptors first: if the first char is 'L' or '[', it is JavaKind.Object and must not go through this method
  2. Use the null-safe sibling fromPrimitiveOrVoidTypeCharOrNull(ch) and branch on null instead of relying on the exception
  3. Validate generated descriptors against the JVM spec letters (Z C F D B S I J V) before parsing

Example fix

// before
JavaKind k = JavaKind.fromPrimitiveOrVoidTypeChar(desc.charAt(0)); // fails on 'L' or '['

// after
JavaKind k = JavaKind.fromPrimitiveOrVoidTypeCharOrNull(desc.charAt(0));
if (k == null) k = (desc.charAt(0) == 'L' || desc.charAt(0) == '[') ? JavaKind.Object : null;
Defensive patterns

Strategy: validation

Validate before calling

JavaKind k = JavaKind.fromPrimitiveOrVoidTypeCharOrNull(ch);
if (k == null && ch != 'L' && ch != '[') throw new IllegalArgumentException("Bad descriptor char: " + ch);

Type guard

static boolean isPrimitiveOrVoidChar(char c) { return "ZCFDBSIJV".indexOf(c) >= 0; }

Try / catch

catch (IllegalArgumentException e) { report the offending descriptor string and index, not just the char }

Prevention

When it happens

Trigger: Calling fromPrimitiveOrVoidTypeChar with the first char of a descriptor without first checking for 'L'/'[' (e.g. feeding 'Ljava/lang/String;' -> 'L'); descriptor strings with a typo like 'l' or 'i' lowercase; empty/garbage descriptor input from bytecode the tool generated.

Common situations: Writing a bytecode parser or generator that assumes every descriptor is primitive; passing class-file descriptors obtained from reflection (getType() char) without filtering reference types; case confusion between JVM spec letters and their lowercase forms.

Related errors


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