{"record":{"id":"32fd929ffc6b97b6","repo":"elastic/elasticsearch","slug":"testclusters-does-not-allow-the-following-settings","errorCode":null,"errorMessage":"Testclusters does not allow the following settings to be changed:{} for {}","messagePattern":"Testclusters does not allow the following settings to be changed:(.+?) for (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java","lineNumber":1453,"sourceCode":"            baseConfig.put(\"cluster.service.slow_master_task_logging_threshold\", \"5s\");\n        }\n\n        // Limit the number of allocated processors for all nodes in the cluster by default.\n        // This is to ensure that the tests run consistently across different environments.\n        String processorCount = shouldConfigureTestClustersWithOneProcessor() ? \"1\" : \"2\";\n        if (getVersion().onOrAfter(\"7.4.0\")) {\n            baseConfig.put(\"node.processors\", processorCount);\n        } else {\n            baseConfig.put(\"processors\", processorCount);\n        }\n\n        baseConfig.put(\"action.destructive_requires_name\", \"false\");\n\n        HashSet<String> overriden = new HashSet<>(baseConfig.keySet());\n        overriden.retainAll(settings.keySet());\n        overriden.removeAll(OVERRIDABLE_SETTINGS);\n        if (overriden.isEmpty() == false) {\n            throw new IllegalArgumentException(\n                \"Testclusters does not allow the following settings to be changed:\" + overriden + \" for \" + this\n            );\n        }\n        // Make sure no duplicate config keys\n        settings.keySet().stream().filter(OVERRIDABLE_SETTINGS::contains).forEach(baseConfig::remove);\n\n        final Path configFileRoot = configFile.getParent();\n        try {\n            Files.writeString(\n                configFile,\n                Stream.concat(settings.entrySet().stream(), baseConfig.entrySet().stream())\n                    .map(entry -> entry.getKey() + \": \" + entry.getValue())\n                    .collect(Collectors.joining(\"\\n\")),\n                StandardOpenOption.TRUNCATE_EXISTING,\n                StandardOpenOption.CREATE\n            );\n\n            final List<Path> configFiles;","sourceCodeStart":1435,"sourceCodeEnd":1471,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java#L1435-L1471","documentation":"Thrown in createConfiguration() when the set of config keys the caller supplied via node.setting(...) overlaps baseConfig keys that are NOT in OVERRIDABLE_SETTINGS. The plugin protects a fixed set of internal config keys (path.data, path.logs, node.name, node.processors, action.destructive_requires_name, etc.) because they are managed by the harness itself.","triggerScenarios":"A test or plugin calls node.setting(\"path.data\", ...) (or any protected key) with a value that conflicts with what the plugin already set in baseConfig. The intersection of the user's settings and baseConfig, minus OVERRIDABLE_SETTINGS, is non-empty.","commonSituations":"A build.gradle adds a setting like 'node.name', 'path.repo', 'processors', 'node.processors', or 'action.destructive_requires_name' via setting(...) — these are all plugin-managed. Usually a copy-paste from an older distributions-test that allowed them.","solutions":["Remove the offending key from your node.setting(...) call — the message names the exact set in 'overriden'.","If you genuinely need to change one of these, check OVERRIDABLE_SETTINGS for the key; if it is listed there it is allowed, otherwise the harness owns it.","For path.data/path.logs, use node.setDataPath(Path) or the dataDir mechanism on RunTask instead of the raw setting.","For cluster name, use the cluster's naming API rather than 'cluster.name' via setting()."],"exampleFix":"// before:\nnode.setting(\"node.processors\", 2);  // protected, throws\n// after:\nnode.setProcessors(2);  // or omit — let the harness compute it","handlingStrategy":"validation","validationCode":"Set<String> conflict = new HashSet<>(yourSettings.keySet());\nconflict.retainAll(BASE_CONFIG_KEYS);  // path.data, node.name, node.processors, ...\nconflict.removeAll(OVERRIDABLE_SETTINGS);\nif (!conflict.isEmpty()) {\n    throw new IllegalArgumentException(\"Refusing protected settings: \" + conflict);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use the dedicated setters (setProcessors, setDataPath, nameCustomization) rather than raw setting() for managed keys.","Check OVERRIDABLE_SETTINGS before assuming a setting is free to change.","Review build.gradle for copy-pasted settings from older distributions-test code."],"tags":["testclusters","config","validation","api-misuse"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}