SonarSource/sonarqube · error · MessageException
a JVM option can't overwrite mandatory JVM options.
Error message
a JVM option can't overwrite mandatory JVM options. %s overwrites %s
What it means
The single-value variant of checkMandatoryOptionOverwrite validates one user-supplied JVM option and throws a MessageException if it would overwrite a mandatory option SonarQube force-sets on the child JVM. The message names both the offending value and the mandatory option (key+value) it would replace.
Solutions
- Delete the colliding option from the user JVM options property
- Let SonarQube control that setting through its dedicated property (e.g. heap-size properties for Elasticsearch)
- Read 'X overwrites Y' in the message to see the reserved option (Y) and remove user option (X)
- Re-check the property after SonarQube upgrades, as the set of mandatory options can grow
Example fix
// before sonar.web.javaOpts=-Xmx1024m -Xms512m // after (non-reserved flags only) sonar.web.javaOpts=-XX:+HeapDumpOnOutOfMemoryError
Defensive patterns
Strategy: validation
Validate before calling
boolean conflictsWithMandatory(String opt, Map<String,String> mandatory) {
return mandatory.keySet().stream().anyMatch(k -> opt.startsWith(k));
} Try / catch
try {
launcher.start();
} catch (MessageException e) {
if (e.getMessage().contains("overwrites")) {
log.error("User JVM option conflicts with a mandatory option", e);
}
} Prevention
- Consult the mandatory option list for each process type before customizing javaOpts
- Keep user JVM options limited to non-reserved tuning flags
- Test javaOpts changes on a staging node first
When it happens
Trigger: Calling addFromMandatoryProperty with a single JVM option string whose key matches a reserved mandatory option, e.g. passing -Xmx or -Xms where the process heap is managed by SonarQube itself.
Common situations: Hand-tuning child process heap or GC flags that newer SonarQube versions reserve, applying the same javaOpts template to all processes when one process has that option reserved.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- a JVM option can't overwrite mandatory JVM options. The…
- a JVM option can't be empty and must start with '-'. The…
- A rule with the key ' ' already exists
- Authentication is required
- Authentication is required
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/d77dc675875aae6b.
Report an issue: GitHub.
Appendix: source
Thrown at server/sonar-main/src/main/java/org/sonar/application/command/JvmOptions.java:129
*
* @throws IllegalArgumentException if argument is empty or does not start with {@code -}.
*/
public T add(String str) {
requireNonNull(str, JVM_OPTION_NOT_NULL_ERROR_MESSAGE);
String value = str.trim();
if (isInvalidOption(value)) {
throw new IllegalArgumentException("a JVM option can't be empty and must start with '-'");
}
checkMandatoryOptionOverwrite(value);
options.add(value);
return castThis();
}
private void checkMandatoryOptionOverwrite(String value) {
Map.Entry<String, String> overriddenMandatoryOption = mandatoryOptionFor(value);
if (overriddenMandatoryOption != null) {
throw new MessageException(String.format(
"a JVM option can't overwrite mandatory JVM options. %s overwrites %s",
value,
overriddenMandatoryOption.getKey() + overriddenMandatoryOption.getValue()));
}
}
@CheckForNull
private Map.Entry<String, String> mandatoryOptionFor(String jvmOption) {
return mandatoryOptions.entrySet().stream()
.filter(s -> jvmOption.startsWith(s.getKey()) && !jvmOption.equals(s.getKey() + s.getValue()))
.findFirst()
.orElse(null);
}
private static boolean isInvalidOption(String value) {
return value.isEmpty() || !value.startsWith("-");
}
View on GitHub (pinned to 184c821202)