elastic/elasticsearch · error · TestClustersException

Invalid jvm argument `{}` configure as systemProperty instea

Error message

Invalid jvm argument `{}` configure as systemProperty instead for {}

What it means

Thrown by getESEnvironment() while building the jvmArgs portion of ES_JAVA_OPTS when a user-supplied JVM argument starts with '-D'. The build reserves -D system properties for the dedicated systemProperty API (which applies the feature_flag guard, ES_PATH_CONF substitution, and netty leak detection append); mixing them into jvmArgs bypasses those safeguards and is rejected.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:857

                .collect(Collectors.joining(" "));
        }
        if (systemProperties.containsKey("io.netty.leakDetection.level") == false) {
            systemPropertiesString = systemPropertiesString + " -Dio.netty.leakDetection.level=paranoid";
        }

        String featureFlagsString = "";
        if (featureFlags.isEmpty() == false && isReleasedVersion.apply(getVersion())) {
            featureFlagsString = featureFlags.stream()
                .filter(f -> getVersion().onOrAfter(f.getFrom()) && (f.getUntil() == null || getVersion().before(f.getUntil())))
                .map(f -> "-D" + f.getFeature() + "=true")
                .collect(Collectors.joining(" "));
        }

        String jvmArgsString = "";
        if (jvmArgs.isEmpty() == false) {
            jvmArgsString = " " + jvmArgs.stream().peek(argument -> {
                if (argument.toString().startsWith("-D")) {
                    throw new TestClustersException(
                        "Invalid jvm argument `" + argument + "` configure as systemProperty instead for " + this
                    );
                }
            }).collect(Collectors.joining(" "));
        }
        String heapSize = System.getProperty("tests.heap.size", "512m");
        defaultEnv.put(
            "ES_JAVA_OPTS",
            "-Xms"
                + heapSize
                + " -Xmx"
                + heapSize
                + " -ea -esa "
                + systemPropertiesString
                + " "
                + featureFlagsString
                + " "
                + jvmArgsString

View on GitHub (pinned to db6a809a66)

Solutions

  1. Move any -D... argument to node.systemProperty(key, value) (stripping the -D prefix).
  2. Keep in jvmArgs only non-property flags: -Xmx, -Xms, -XX:..., -ea, etc.
  3. If you need ES_PATH_CONF interpolation, note that systemProperty supports the ${ES_PATH_CONF} placeholder; jvmArgs does not.
  4. Audit existing jvmArgs calls and split them by prefix.

Example fix

// before: -D passed as jvm arg
jvmArgs('-Des.foo=bar', '-Xmx2g')
// after: split into systemProperty + jvm arg
systemProperty('es.foo', 'bar')
jvmArgs('-Xmx2g')
Defensive patterns

Strategy: validation

Validate before calling

static List<CharSequence> splitJvmAndSystemProperties(List<CharSequence> raw) {
    List<CharSequence> jvm = new ArrayList<>();
    for (CharSequence a : raw) {
        String s = a.toString();
        if (s.startsWith("-D") && s.contains("=")) {
            // route to systemProperty instead; caller should handle
            throw new IllegalArgumentException("Use systemProperty for -D arg: " + s);
        }
        jvm.add(a);
    }
    return jvm;
}
// Use: node.jvmArgs(splitJvmAndSystemProperties(args).toArray(new CharSequence[0]));

Type guard

static boolean isPureJvmArg(CharSequence a) {
    return a != null && !a.toString().startsWith("-D");
}

Prevention

When it happens

Trigger: Calling node.jvmArgs('-Des.foo=bar') or any argument whose string form starts with '-D'. The check is a prefix match, so even '-Dfoo' (no '=') is rejected. Fires lazily when getESEnvironment() runs.

Common situations: Copy-pasting JAVA_OPTS from production into the test cluster. Migrating from a generic Gradle exec to the testcluster API. Assuming jvmArgs and systemProperty are interchangeable.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/a007d37a89afdac0. Report an issue: GitHub.