oracle/graal · error · ParserException.ClassFormatError

Invalid method signature: {}

Error message

Invalid method signature: {}

What it means

SignatureSymbols.parse splits a method signature descriptor such as '(ILjava/lang/String;)V' into parameter and return types. The very first check requires length >= 3 and a leading '('; anything shorter or not starting with '(' throws ClassFormatError 'Invalid method signature: <sig>'.

Source

Thrown at espresso-shared/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/SignatureSymbols.java:202

        if (type == ParserTypes.java_lang_Object || TypeSymbols.isArray(type)) {
            return ParserTypes.java_lang_Object;
        } else if (type == ParserTypes._int || type == ParserTypes._short || type == ParserTypes._boolean || type == ParserTypes._char) {
            return ParserTypes._int;
        } else {
            return type;
        }
    }

    /**
     * Parses a signature descriptor string into its parameter and return type components.
     *
     * @return the parsed parameter types followed by the return type.
     * @throws ParserException.ClassFormatError if {the signature is not well-formed
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static Symbol<Type>[] parse(TypeSymbols typeSymbols, Symbol<Signature> signature) throws ParserException.ClassFormatError {
        if ((signature.length() < 3) || signature.byteAt(0) != '(') {
            throw new ParserException.ClassFormatError("Invalid method signature: " + signature);
        }
        final List<Symbol<Type>> buf = new ArrayList<>();
        int i = 1;
        while (signature.byteAt(i) != ')') {
            final Symbol<Type> descriptor = typeSymbols.parse(signature, i, true);
            buf.add(descriptor);
            i = i + descriptor.length();
            if (i >= signature.length()) {
                throw new ParserException.ClassFormatError("Invalid method signature: " + signature);
            }
        }
        i++;
        final Symbol<Type> descriptor = typeSymbols.parse(signature, i, true);
        if (i + descriptor.length() != signature.length()) {
            throw new ParserException.ClassFormatError("Invalid method signature: " + signature);
        }
        final Symbol<Type>[] descriptors = buf.toArray(new Symbol[buf.size() + 1]);
        descriptors[buf.size()] = descriptor;

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Ensure the signature is a full method descriptor: starts with '(', ends with a return type, minimal valid form is '()V'
  2. If you hold a field descriptor, wrap or re-fetch the method descriptor rather than reusing the field type
  3. Add a cheap pre-check: sig.length() >= 3 && sig.charAt(0) == '(' before parsing

Example fix

// before
Symbol<Type>[] parts = SignatureSymbols.parse(types, fieldDescriptor); // e.g. "I"

// after
Symbol<Type>[] parts = SignatureSymbols.parse(types, methodDescriptor); // e.g. "(I)V"
Defensive patterns

Strategy: validation

Validate before calling

if (sig.length() < 3 || sig.charAt(0) != '(') throw new IllegalArgumentException("Not a method signature: " + sig);

Type guard

static boolean looksLikeMethodSignature(String s) { return s != null && s.length() >= 3 && s.charAt(0) == '(' && s.indexOf(')') > 0; }

Try / catch

catch (ParserException.ClassFormatError e) { report the offending signature and where it came from (class/method) }

Prevention

When it happens

Trigger: Passing a signature like 'V', '()', '(I', or a field descriptor by mistake (e.g. 'I' or 'Ljava/lang/String;') where a method signature is required; truncated signature strings from generated bytecode.

Common situations: Using a field type descriptor where the method signature slot is expected (common in generated-proxies/serialization code); empty signature from a failed lookup; off-by-one string slicing when concatenating descriptors.

Related errors


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