{"record":{"id":"432d3532de9f5bf4","repo":"SonarSource/sonarqube","slug":"a-jvm-option-can-t-overwrite-mandatory-jvm-options","errorCode":null,"errorMessage":"a JVM option can't overwrite mandatory JVM options. The following JVM options defined by property '%s' are invalid: %s","messagePattern":"a JVM option can't overwrite mandatory JVM options\\. The following JVM options defined by property '(.+?)' are invalid: (.+?)","errorType":"validation","errorClass":"MessageException","httpStatus":null,"severity":"error","filePath":"server/sonar-main/src/main/java/org/sonar/application/command/JvmOptions.java","lineNumber":99,"sourceCode":"    List<String> invalidOptions = jvmOptionsFromProperty.stream()\n      .filter(JvmOptions::isInvalidOption)\n      .toList();\n    if (!invalidOptions.isEmpty()) {\n      throw new MessageException(format(\n        \"a JVM option can't be empty and must start with '-'. The following JVM options defined by property '%s' are invalid: %s\",\n        propertyName,\n        invalidOptions.stream()\n          .collect(joining(\", \"))));\n    }\n  }\n\n  private void checkMandatoryOptionOverwrite(String propertyName, List<String> jvmOptionsFromProperty) {\n    List<Match> matches = jvmOptionsFromProperty.stream()\n      .map(jvmOption -> new Match(jvmOption, mandatoryOptionFor(jvmOption)))\n      .filter(match -> match.mandatoryOption() != null)\n      .toList();\n    if (!matches.isEmpty()) {\n      throw new MessageException(format(\n        \"a JVM option can't overwrite mandatory JVM options. The following JVM options defined by property '%s' are invalid: %s\",\n        propertyName,\n        matches.stream()\n          .map(m -> m.option() + \" overwrites \" + m.mandatoryOption.getKey() + m.mandatoryOption.getValue())\n          .collect(joining(\", \"))));\n    }\n  }\n\n  /**\n   * Add an option.\n   * Argument is trimmed before being added.\n   *\n   * @throws IllegalArgumentException if argument is empty or does not start with {@code -}.\n   */\n  public T add(String str) {\n    requireNonNull(str, JVM_OPTION_NOT_NULL_ERROR_MESSAGE);\n    String value = str.trim();\n    if (isInvalidOption(value)) {","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-main/src/main/java/org/sonar/application/command/JvmOptions.java#L81-L117","documentation":"JvmOptions.checkMandatoryOptionOverwrite (list variant) rejects user-provided JVM options that collide with options SonarQube sets mandatorily for a child process. If any property-sourced option would overwrite a mandatory key (e.g. a user -Xms/-Xmx conflicting with reserved ES options), a MessageException lists each 'option overwrites mandatory' pair.","triggerScenarios":"Setting a JVM options property (sonar.web.javaOpts, sonar.ce.javaOpts, sonar.search.javaOpts) with an option whose key matches a mandatory option for that process — for example providing sonar.search.javaOpts values that conflict with options SonarQube force-sets for Elasticsearch (like -Xms/-Xmx managed via sonar.search.javaOpts restrictions or heap settings).","commonSituations":"Users trying to tune heap size for Elasticsearch directly in javaOpts while SonarQube manages it via sonar.search.javaHeapXxx properties, or migrating old configs that manually set options now reserved by newer SonarQube versions.","solutions":["Remove the conflicting option from the javaOpts property","Use the dedicated SonarQube property for that setting instead (e.g. sonar.search.javaOpts → sonar.search.javaOpts restrictions or the dedicated heap properties)","Review the error message: each 'X overwrites Y' pair tells you exactly which user option collides with which mandatory option","After upgrading SonarQube, re-audit javaOpts properties against the new mandatory option list"],"exampleFix":"// before\nsonar.search.javaOpts=-Xms4G -Xmx4G  (overwrites managed heap)\n// after\nsonar.search.javaHeapSize=4096\nsonar.search.javaOpts=-XX:+UseG1GC","handlingStrategy":"validation","validationCode":"Set<String> reserved = Set.of(\"-Xms\", \"-Xmx\", \"-XX:+HeapDumpOnOutOfMemoryError\"); // per-process mandatory set\nboolean conflicts = List.of(javaOptsProperty.split(\"\\\\s+\")).stream()\n  .anyMatch(o -> reserved.stream().anyMatch(r -> o.startsWith(r)));","typeGuard":null,"tryCatchPattern":"try {\n  launcher.start();\n} catch (MessageException e) {\n  if (e.getMessage().contains(\"can't overwrite mandatory JVM options\")) {\n    log.error(\"Remove options that collide with mandatory JVM options\", e);\n  }\n}","preventionTips":["Never set heap flags manually where SonarQube provides dedicated properties","Re-audit javaOpts properties after each SonarQube upgrade","Use only tuning flags (GC, diagnostics) in javaOpts, not reserved keys"],"tags":["java","jvm","configuration-conflict"],"backgroundTag":"conflicting-config-options","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}