oracle/graal · error · IllegalArgumentException

Signature must start with a '(':

Error message

Signature must start with a '(': 

What it means

IllegalArgumentException from SignatureUtil.parseSignatureInternal: the descriptor does not start with '(' — the mandatory opening parenthesis of a JVMS 4.3.3 method descriptor. SignatureUtil only accepts full method descriptors '(params)return', so a bare type descriptor such as 'I' or 'Ljava/lang/String;' (valid as a field descriptor, not a method descriptor) is rejected.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/SignatureUtil.java:141

        }
    }

    /**
     * Checks if the given signature can be successfully parsed by
     * {@link #parseSignature(String, List)}.
     *
     * @param signature the signature to check
     * @param acceptMissingReturnType whether a signature without a return type is considered to be
     *            valid
     * @return whether the signature can be successfully parsed
     */
    public static boolean isSignatureValid(String signature, boolean acceptMissingReturnType) {
        return parseSignatureInternal(signature, null, false, acceptMissingReturnType) != null;
    }

    private static <T> T throwOrReturn(boolean shouldThrow, T returnValue, String errorMessage) {
        if (shouldThrow) {
            throw new IllegalArgumentException(errorMessage);
        } else {
            return returnValue;
        }
    }
}

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Wrap the value as a method descriptor if it is meant to be a parameter/return type: '(I)V' not 'I'.
  2. If you have a Java-source signature, convert it with a proper parser (e.g. MetaAccessProvider.parseMethodDescriptor or bytecode-tooling helpers) instead of string surgery.
  3. Pre-check with SignatureUtil.isSignatureValid(sig, false) on untrusted input.

Example fix

// before
String ret = SignatureUtil.parseSignature("I", params);

// after
String ret = SignatureUtil.parseSignature("(I)V", params); // full method descriptor
Defensive patterns

Strategy: validation

Validate before calling

if (sig == null || sig.isEmpty() || sig.charAt(0) != '(') {
    throw new IllegalArgumentException("expected method descriptor like (I)V, got: " + sig);
}

Type guard

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

Try / catch

try {
    SignatureUtil.parseSignature(sig, params);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Signature must start")) {
        sig = "(" + sig + ")V"; // only if you knowingly held a bare type descriptor
    } else throw e;
}

Prevention

When it happens

Trigger: Calling SignatureUtil.parseSignature with a field-type descriptor ('I', 'Ljava/lang/String;'), a human-readable signature ('void foo(int)'), or a string that lost its leading '(' in preprocessing.

Common situations: Confusing field descriptors with method descriptors when reading class-file metadata; passing a Java-source-style signature where a bytecode descriptor is required; off-by-one substring that drops the first character.

Related errors


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