{"record":{"id":"3f7c4a18e0889709","repo":"elastic/elasticsearch","slug":"variantprefixes-variantbaseclasses-and-variantsp","errorCode":null,"errorMessage":"variantPrefixes, variantBaseClasses, and variantSpecFilePatterns must have the same length","messagePattern":"variantPrefixes, variantBaseClasses, and variantSpecFilePatterns must have the same length","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/esql/GenerateEsqlSpecTestsTask.java","lineNumber":100,"sourceCode":"    public abstract FileSystemOperations getFileSystemOperations();\n\n    @TaskAction\n    public void generate() throws IOException {\n        File outputDir = getOutputDirectory().getAsFile().get();\n        getFileSystemOperations().delete(spec -> spec.delete(outputDir));\n\n        String packageName = getPackageName().get();\n        String packagePath = packageName.replace('.', '/');\n        File packageDir = new File(outputDir, packagePath);\n        if (packageDir.mkdirs() == false && packageDir.exists() == false) {\n            throw new IOException(\"Could not create directory: \" + packageDir);\n        }\n\n        List<String> prefixes = getVariantPrefixes().get();\n        List<String> baseClasses = getVariantBaseClasses().get();\n        List<String> allEncodedPatterns = getVariantSpecFilePatterns().get();\n        if (prefixes.size() != baseClasses.size() || prefixes.size() != allEncodedPatterns.size()) {\n            throw new IllegalStateException(\"variantPrefixes, variantBaseClasses, and variantSpecFilePatterns must have the same length\");\n        }\n\n        File specDir = getSpecFilesDir().getAsFile().get();\n        File[] specFiles = specDir.listFiles((dir, name) -> name.endsWith(\".csv-spec\"));\n        if (specFiles == null) {\n            return;\n        }\n        Arrays.sort(specFiles);\n        for (File specFile : specFiles) {\n            String specFileName = specFile.getName();\n            String baseName = specFileName.substring(0, specFileName.length() - \".csv-spec\".length());\n            String pascalName = toPascalCase(baseName);\n            for (int i = 0; i < prefixes.size(); i++) {\n                String encoded = allEncodedPatterns.get(i);\n                List<String> patterns = encoded.isEmpty() ? List.of() : Arrays.asList(encoded.split(\",\"));\n                if (patterns.isEmpty() == false && matchesAnyPattern(specFile, patterns) == false) {\n                    continue;\n                }","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/esql/GenerateEsqlSpecTestsTask.java#L82-L118","documentation":"Thrown by GenerateEsqlSpecTestsTask.generate() when the three parallel List properties — variantPrefixes, variantBaseClasses, and variantSpecSpecFilePatterns — have different sizes. These lists are zipped together to generate variant spec test classes, so they must have equal length. The check is performed after all three are materialized from their Provider wrappers.","triggerScenarios":"The task is configured with mismatched list sizes for its variant properties. For example, variantPrefixes has 2 entries, variantBaseClasses has 3, and variantSpecFilePatterns has 2. This is a configuration-time error that surfaces at task execution time when the properties are read.","commonSituations":"A build engineer adds a new variant to variantPrefixes but forgets to add the corresponding entry in variantBaseClasses or variantSpecFilePatterns. The properties are configured from different sources (one from a file, another from a hardcoded list) that drift in length. Copy-paste error when duplicating a variant configuration block.","solutions":["Inspect the task configuration in build.gradle and ensure all three lists have the same number of entries.","If lists are generated programmatically, add an assertion in the configuration block: assert prefixes.size() == baseClasses.size() && prefixes.size() == patterns.size().","Log the three list sizes before the task runs to diagnose which list is short: println variantPrefixes.get().size()."],"exampleFix":"// before\ngenerateEsqlSpecTests {\n    variantPrefixes = ['Plain', 'Text', 'Spatial']\n    variantBaseClasses = ['PlainBase', 'TextBase'] // missing Spatial\n    variantSpecFilePatterns = ['**/plain*.csv-spec', '**/text*.csv-spec', '**/spatial*.csv-spec']\n}\n\n// after\ngenerateEsqlSpecTests {\n    variantPrefixes = ['Plain', 'Text', 'Spatial']\n    variantBaseClasses = ['PlainBase', 'TextBase', 'SpatialBase']\n    variantSpecFilePatterns = ['**/plain*.csv-spec', '**/text*.csv-spec', '**/spatial*.csv-spec']\n}","handlingStrategy":"validation","validationCode":"// Assert list sizes at configuration time\nassert variantPrefixes.get().size() == variantBaseClasses.get().size() :\n    'variantPrefixes and variantBaseClasses must have the same size'\nassert variantPrefixes.get().size() == variantSpecFilePatterns.get().size() :\n    'variantPrefixes and variantSpecFilePatterns must have the same size'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When adding a variant, update all three lists in the same edit.","Add a configuration-time assertion so the error surfaces earlier (at configure, not execute).","Use a single list of objects/tuples instead of three parallel lists to make mismatches impossible."],"tags":["esql","code-generation","configuration","validation","build-task"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}