{"record":{"id":"6754090615191a7d","repo":"elastic/elasticsearch","slug":"template-property-not-found-in-template","errorCode":null,"errorMessage":"Template property '{}' not found in template:\n{}","messagePattern":"Template property '(.+?)' not found in template:\n(.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java","lineNumber":1502,"sourceCode":"        }\n\n        tweakJvmOptions(configFileRoot);\n        LOGGER.info(\"Written config file:{} for {}\", configFile, this);\n    }\n\n    private void tweakJvmOptions(Path configFileRoot) {\n        LOGGER.info(\"Tweak jvm options {}.\", configFileRoot.resolve(\"jvm.options\"));\n        Path jvmOptions = configFileRoot.resolve(\"jvm.options\");\n        try {\n            String content = new String(Files.readAllBytes(jvmOptions));\n            Map<ReplacementKey, String> expansions = jvmOptionExpansions();\n            for (var entry : expansions.entrySet()) {\n                ReplacementKey replacement = entry.getKey();\n                String key = replacement.key();\n                if (content.contains(key) == false) {\n                    key = replacement.fallback();\n                    if (content.contains(key) == false) {\n                        throw new IOException(\"Template property '\" + replacement + \"' not found in template:\\n\" + content);\n                    }\n                }\n                content = content.replace(key, entry.getValue());\n            }\n            Files.write(jvmOptions, content.getBytes());\n        } catch (IOException ioException) {\n            throw new UncheckedIOException(ioException);\n        }\n    }\n\n    private record ReplacementKey(String key, String fallback) {}\n\n    private Map<ReplacementKey, String> jvmOptionExpansions() {\n        Map<ReplacementKey, String> expansions = new HashMap<>();\n        Version version = getVersion();\n\n        ReplacementKey heapDumpPathSub;\n        if (version.before(\"8.19.0\") && version.onOrAfter(\"6.3.0\")) {","sourceCodeStart":1484,"sourceCodeEnd":1520,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java#L1484-L1520","documentation":"Thrown in tweakJvmOptions when a ReplacementKey's expected placeholder is not found in the distro's jvm.options file, after trying both the primary key and the fallback. The plugin rewrites specific jvm.options lines (heap, ErrorFile, GC logs) by string replacement; if the template changed shape, the replacement cannot proceed safely.","triggerScenarios":"jvmOptionExpansions() returns a ReplacementKey whose key() and fallback() strings are both absent from the read jvm.options content. Happens when the ES distribution version changed the jvm.options format (renamed a flag, changed a path) and the build-tools' expected template has not been updated to match.","commonSituations":"Bumping the ES version under test without updating build-tools; backporting changes where the old jvm.options format differs; a custom distribution ships a non-standard jvm.options.","solutions":["Open the distro's jvm.options file (getDistroDir()/config/jvm.options) and find the line that should contain the placeholder.","Update the ReplacementKey in jvmOptionExpansions() to match the actual current template string.","If the placeholder genuinely moved, add a new fallback key covering the older format for backport compatibility.","Re-extract the distro in case it is stale relative to the current source."],"exampleFix":"// before: ES changed ErrorFile path format\nerrorFileSub = new ReplacementKey(\"-XX:ErrorFile=logs/hs_err_pid%p.log\", null);\n// after: cover both old and new formats\nerrorFileSub = new ReplacementKey(\"-XX:ErrorFile=logs/hs_err_pid%p.log\", \"-XX:ErrorFile=hs_err_pid%p.log\");","handlingStrategy":"validation","validationCode":"String tmpl = Files.readString(jvmOptions);\nfor (var e : jvmOptionExpansions().entrySet()) {\n    ReplacementKey rk = e.getKey();\n    if (!tmpl.contains(rk.key()) && (rk.fallback() == null || !tmpl.contains(rk.fallback()))) {\n        throw new IllegalStateException(\"jvm.options template missing placeholder for \" + rk);\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When bumping the ES version under test, diff the distro's jvm.options against the previous one and update ReplacementKeys accordingly.","Keep a fallback key for backport compatibility when formats diverge.","Re-extract the distro if templates look stale."],"tags":["testclusters","jvm-options","version-mismatch","template"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}