oracle/graal · error · IllegalArgumentException

Invalid VM option %s specified. %s

Error message

Invalid VM option %s specified. %s

What it means

Thrown by EspressoExternalVMAccessBuilder after an option key was recognized: the raw string value failed descriptor.getKey().getType().convert(value). Each option has a typed key (boolean, enum, int, string...), so a syntactically valid key with a wrong-typed value is rejected with IllegalArgumentException including the convert error.

Source

Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalVMAccessBuilder.java:224

                } catch (IOException e) {
                    throw new IllegalArgumentException("Cannot use the specified log.file", e);
                }
                builder.logHandler(out);
                return;
            }
        }
        OptionDescriptor descriptor = findOptionDescriptor(group, key);
        if (descriptor == null) {
            key = JAVA_LANGUAGE_ID + "." + key;
            descriptor = findOptionDescriptor(JAVA_LANGUAGE_ID, key);
            if (descriptor == null) {
                throw new IllegalArgumentException("Unrecognized VM option: '" + vmOption);
            }
        }
        try {
            descriptor.getKey().getType().convert(value);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(String.format("Invalid VM option %s specified. %s", vmOption, e.getMessage()));
        }
        builder.option(key, value);
    }

    private static OptionDescriptor findOptionDescriptor(String group, String key) {
        OptionDescriptors descriptors = null;
        switch (group) {
            case "engine":
            case "compiler":
                descriptors = getTempEngine().getOptions();
                break;
            default:
                Engine engine = getTempEngine();
                if (engine.getLanguages().containsKey(group)) {
                    descriptors = engine.getLanguages().get(group).getOptions();
                } else if (engine.getInstruments().containsKey(group)) {
                    descriptors = engine.getInstruments().get(group).getOptions();
                }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Read the option's declared type from its OptionDescriptor and supply the value in the exact expected syntax (booleans are 'true'/'false', enums use the exact constant name, numbers in plain decimal)
  2. Strip surrounding quotes/whitespace that shells or properties loaders may have left in the value
  3. Validate candidate values with the same convert() call in a pre-flight loop so all bad values are reported before the engine starts

Example fix

// before
builder.option("engine.WarnInterpreterOnly", "no"); // not a boolean literal

// after
builder.option("engine.WarnInterpreterOnly", "false");
Defensive patterns

Strategy: validation

Validate before calling

OptionDescriptor d = findOptionDescriptor(group, key);
d.getKey().getType().convert(value); // pre-flight: throws the same convert error early with your context

Try / catch

catch (IllegalArgumentException e) { include key, value, and the option's declared type in the error report }

Prevention

When it happens

Trigger: Passing e.g. 'engine.Compilation=false' style mistakes like a non-numeric value to a numeric option, an unknown enum constant to an enum option, or 'yes'/'1' to a strictly boolean option expecting 'true'/'false'.

Common situations: Assuming loose truthy parsing ('yes', 'on', '1') for boolean options; passing arbitrary strings to enum-typed Espresso options; locale-specific number formats; values quoted incorrectly when options come from a properties file or shell.

Related errors


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