oracle/graal · error · IllegalArgumentException

Invalid JDWP option value: {key} can be only 'y' or 'n'.

Error message

Invalid JDWP option value: {key} can be only 'y' or 'n'.

What it means

Inside the JDWPOptions OptionType converter, yesOrNo() validates that boolean JDWP keys ('server', 'suspend', 'includevirtualthreads') have exactly the single-letter value 'y' or 'n'. Any other value (yes/no, true/false, 1/0) is rejected.

Source

Thrown at espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java:400

    @Option(help = "Minimum number of locals to run liveness analysis.\\n" + //
                    "Liveness analysis, if enabled, only affects compiled code.", //
                    category = OptionCategory.EXPERT, //
                    stability = OptionStability.EXPERIMENTAL, //
                    usageSyntax = "[0, 65535]") //
    public static final OptionKey<Integer> LivenessAnalysisMinimumLocals = new OptionKey<>(8);

    @Option(help = "Enable Class Hierarchy Analysis, which optimizes instanceof checks and virtual method calls by keeping track of descendants of a given class or interface.", //
                    category = OptionCategory.EXPERT, //
                    stability = OptionStability.EXPERIMENTAL, //
                    usageSyntax = "false|true") //
    public static final OptionKey<Boolean> CHA = new OptionKey<>(true);

    private static final OptionType<com.oracle.truffle.espresso.jdwp.api.JDWPOptions> JDWP_OPTIONS_OPTION_TYPE = new OptionType<>("JDWPOptions", new Function<String, JDWPOptions>() {

        private boolean yesOrNo(String key, String value) {
            if (!"y".equals(value) && !"n".equals(value)) {
                throw new IllegalArgumentException("Invalid JDWP option value: " + key + " can be only 'y' or 'n'.");
            }
            return "y".equals(value);
        }

        @Override
        public JDWPOptions apply(String s) {
            final String[] options = s.split(",");
            String transport = null;
            String host = null;
            int port = 0;
            boolean server = false;
            boolean suspend = true;

            for (String keyValue : options) {
                int equalsIndex = keyValue.indexOf('=');
                if (equalsIndex <= 0) {
                    throw new IllegalArgumentException("JDWP options must be a comma separated list of key=value pairs.");
                }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Use single letters exactly: server=y, suspend=n.
  2. Drop the key entirely when the default is acceptable (suspend defaults to y, server to n).
  3. Validate the option string with a regex before launching.

Example fix

# before
--vm.D...=... --java.JDWPOptions=transport=dt_socket,server=yes,address=:8000

# after
--java.JDWPOptions=transport=dt_socket,server=y,address=:8000
Defensive patterns

Strategy: validation

Validate before calling

for (String kv : opts.split(",")) {
    String[] p = kv.split("=", 2);
    if (Set.of("server","suspend","includevirtualthreads").contains(p[0])
            && !p[1].equals("y") && !p[1].equals("n")) {
        throw new ConfigException(kv + " must be y or n");
    }
}

Type guard

static boolean validJdwp(String s) {
    return s.matches("([a-z]+=(y|n|dt_socket|[\w.\[\]:]*\d+),?)*");
}

Prevention

When it happens

Trigger: Setting --java.JDWPOptions=...,server=yes or suspend=true, or using 'Y'/'N' uppercase - the check is case-sensitive exact match on 'y'/'n'.

Common situations: Copy-pasting agentlib strings from tutorials that use yes/no; translating JDWP options from other tools' formats; uppercase normalization by config management tools.

Related errors


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