SonarSource/sonarqube · error · MessageException
a JVM option can't be empty and must start with '-'. The fol
Error message
a JVM option can't be empty and must start with '-'. The following JVM options defined by property '%s' are invalid: %s
What it means
JvmOptions.checkOptionFormat validates JVM options sourced from a SonarQube property before they are applied to a child process. Each option must be non-empty and start with '-'; any entry failing this check causes a MessageException listing the offending values, preventing misconfigured JVM flags from breaking process startup.
Source
Thrown at server/sonar-main/src/main/java/org/sonar/application/command/JvmOptions.java:85
public T addFromMandatoryProperty(Props props, String propertyName) {
String value = props.nonNullValue(propertyName);
if (!value.isEmpty()) {
String splitRegex = " (?=-)";
List<String> jvmOptions = Arrays.stream(value.split(splitRegex)).map(String::trim).toList();
checkOptionFormat(propertyName, jvmOptions);
checkMandatoryOptionOverwrite(propertyName, jvmOptions);
options.addAll(jvmOptions);
}
return castThis();
}
private static void checkOptionFormat(String propertyName, List<String> jvmOptionsFromProperty) {
List<String> invalidOptions = jvmOptionsFromProperty.stream()
.filter(JvmOptions::isInvalidOption)
.toList();
if (!invalidOptions.isEmpty()) {
throw new MessageException(format(
"a JVM option can't be empty and must start with '-'. The following JVM options defined by property '%s' are invalid: %s",
propertyName,
invalidOptions.stream()
.collect(joining(", "))));
}
}
private void checkMandatoryOptionOverwrite(String propertyName, List<String> jvmOptionsFromProperty) {
List<Match> matches = jvmOptionsFromProperty.stream()
.map(jvmOption -> new Match(jvmOption, mandatoryOptionFor(jvmOption)))
.filter(match -> match.mandatoryOption() != null)
.toList();
if (!matches.isEmpty()) {
throw new MessageException(format(
"a JVM option can't overwrite mandatory JVM options. The following JVM options defined by property '%s' are invalid: %s",
propertyName,
matches.stream()
.map(m -> m.option() + " overwrites " + m.mandatoryOption.getKey() + m.mandatoryOption.getValue())View on GitHub (pinned to 184c821202)
Solutions
- Prefix every option in the property with '-'; e.g. change Xmx2G to -Xmx2G
- Remove empty entries, stray commas and extra whitespace from the property value
- Validate the property value with the code below before startup
- Restart and confirm the child process JVM receives the corrected options
Example fix
// before sonar.web.javaOpts=Xmx2G -XX:MaxMetaspaceSize=512M // after sonar.web.javaOpts=-Xmx2G -XX:MaxMetaspaceSize=512M
Defensive patterns
Strategy: validation
Validate before calling
List<String> opts = List.of(javaOptsProperty.split("\\s+"));
List<String> bad = opts.stream()
.filter(o -> o.isEmpty() || !o.startsWith("-"))
.toList();
if (!bad.isEmpty()) throw new IllegalArgumentException("invalid JVM options: " + bad); Try / catch
try {
launcher.start();
} catch (MessageException e) {
if (e.getMessage().contains("must start with '-'")) {
log.error("Fix javaOpts property formatting", e);
}
} Prevention
- Always prefix JVM flags with '-' in javaOpts properties
- Avoid stray commas/double spaces in property values
- Lint sonar.properties values before deploying
When it happens
Trigger: Setting a JVM options property (e.g. sonar.web.javaOpts, sonar.ce.javaOpts, sonar.search.javaOpts) with empty entries, values missing the leading dash (like 'Xmx2G' instead of '-Xmx2G'), or stray spaces/commas producing empty tokens.
Common situations: Copy-pasting JVM flags from documentation without the leading '-', trailing commas or double spaces in the property value, or leaving an empty value that still yields an empty list element after splitting.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- a JVM option can't overwrite mandatory JVM options. The foll
- a JVM option can't overwrite mandatory JVM options. %s overw
- Unknown severity: %s
- me.getMessage() (invalid offset date-time parameter passed t
- Bad sort field:
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/10d8ed84192af787.
Report an issue: GitHub.