{"record":{"id":"d8a13ea4e8cde454","repo":"oracle/graal","slug":"s-option-s-must-have-s-value-not-s-tostrin","errorCode":null,"errorMessage":"%s option '%s' must have %s value, not %s [toString: %s]","messagePattern":"(.+?) option '(.+?)' must have (.+?) value, not (.+?) \\[toString: (.+?)\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler.options/src/jdk/graal/compiler/options/OptionsParser.java","lineNumber":228,"sourceCode":"            }\n            throw new IllegalArgumentException(msg.toString());\n        }\n\n        Object value = parseOptionValue(desc, uncheckedValue);\n\n        desc.getOptionKey().update(values, value);\n    }\n\n    /**\n     * Parses a given option value with a known descriptor.\n     */\n    public static Object parseOptionValue(OptionDescriptor desc, Object uncheckedValue) {\n        Class<?> optionType = desc.getOptionValueType();\n        Object value;\n        if (!(uncheckedValue instanceof String valueString)) {\n            if (optionType != uncheckedValue.getClass()) {\n                String type = optionType.getSimpleName();\n                throw new IllegalArgumentException(type + \" option '\" + desc.getName() + \"' must have \" + type + \" value, not \" + uncheckedValue.getClass() + \" [toString: \" + uncheckedValue + \"]\");\n            }\n            value = uncheckedValue;\n        } else {\n            if (optionType == Boolean.class) {\n                if (\"true\".equals(valueString)) {\n                    value = Boolean.TRUE;\n                } else if (\"false\".equals(valueString)) {\n                    value = Boolean.FALSE;\n                } else {\n                    throw new IllegalArgumentException(\"Boolean option '\" + desc.getName() + \"' must have value \\\"true\\\" or \\\"false\\\", not \\\"\" + uncheckedValue + \"\\\"\");\n                }\n            } else if (optionType == String.class) {\n                value = valueString;\n            } else if (Enum.class.isAssignableFrom(optionType)) {\n                value = ((EnumOptionKey<?>) desc.getOptionKey()).valueOf(valueString);\n            } else if (optionType == EconomicSet.class) {\n                value = ((EnumMultiOptionKey<?>) desc.getOptionKey()).valueOf(valueString);\n            } else {","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler.options/src/jdk/graal/compiler/options/OptionsParser.java#L210-L246","documentation":"Thrown by OptionsParser.parseOptionValue when the value object is not a String and its runtime class does not exactly equal the option's declared type. When values arrive as Strings they go through per-type parsing, but non-String values (used when options are set programmatically via an EconomicMap rather than parsed from text) must already be the exact boxed type (Boolean, Integer, Long, Float, Double, etc.).","triggerScenarios":"Calling parseOptionValue(desc, someObject) where someObject is, say, an Integer for a Long-typed option (Integer.class != Long.class), a primitive-converted Short, or an arbitrary object. Note the comparison is exact-class equality, not instanceof, so subclasses and wider/narrower numeric boxes all fail.","commonSituations":"Programmatically seeding option maps from untyped config (JSON/YAML numbers parsed as Integer when the option is Long); passing an enum's name String where an EnumOptionKey expects the Enum instance is fine (String branch), but passing a boxed Integer where Boolean is expected fails; reflective code pulling values from a Map<Object,Object>.","solutions":["Convert the value to the exact declared type shown in the message (e.g. ((Number)v).longValue() for a Long option).","Prefer passing the value as a String and let parseOptionValue do the typed parsing (String branch handles Boolean/Enum/numbers).","When loading config generically, coerce numeric types to the option type from desc.getOptionValueType().","Check the '[toString: ...]' part of the message to confirm what object actually arrived."],"exampleFix":"// before\nOptionDescriptor d = ...; // option type Long\nObject v = 42;           // Integer\nObject parsed = OptionsParser.parseOptionValue(d, v);\n\n// after\nObject v = Long.valueOf(42);        // exact Long\n// or simply pass the string form:\nObject parsed = OptionsParser.parseOptionValue(d, \"42\");","handlingStrategy":"type-guard","validationCode":"Object coerceToOptionType(OptionDescriptor desc, Object v) {\n    Class<?> t = desc.getOptionValueType();\n    if (v instanceof String s) return OptionsParser.parseOptionValue(desc, s);\n    if (t == Long.class && v instanceof Number n) return n.longValue();\n    if (t == Integer.class && v instanceof Number n) return n.intValue();\n    if (t == Double.class && v instanceof Number n) return n.doubleValue();\n    if (t == Float.class && v instanceof Number n) return n.floatValue();\n    if (t == Boolean.class && v instanceof Boolean) return v;\n    if (v != null && v.getClass() == t) return v;\n    throw new IllegalArgumentException(\"Cannot coerce \" + v + \" to \" + t.getSimpleName());\n}","typeGuard":"boolean matchesOptionType(OptionDescriptor desc, Object v) {\n    return v != null && v.getClass() == desc.getOptionValueType();\n}","tryCatchPattern":"try {\n    value = OptionsParser.parseOptionValue(desc, uncheckedValue);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"must have\") && e.getMessage().contains(\"[toString:\")) {\n        value = OptionsParser.parseOptionValue(desc, String.valueOf(uncheckedValue)); // re-parse from string form\n    } else throw e;\n}","preventionTips":["Prefer String values when feeding options programmatically; the parser then converts per-type.","Coerce generic config numbers (JSON/YAML) to the exact boxed type from getOptionValueType().","Remember the check is exact class equality: subclasses and Integer-for-Long both fail."],"tags":["graalvm","options","type-mismatch","illegal-argument"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}