elastic/elasticsearch · error · IllegalArgumentException

Duplicate version constants {v1}

Error message

Duplicate version constants {v1}

What it means

Thrown inside the Collectors.toMap merge function in UpdateVersionsTask while scanning Version.java field declarations: two distinct fields both parsed to the same Version value. This indicates a real duplication defect in the Version constants source file.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/UpdateVersionsTask.java:139

        }
    }

    @VisibleForTesting
    static Optional<CompilationUnit> addVersionConstant(CompilationUnit versionJava, Version version, boolean updateCurrent) {
        String newFieldName = toVersionField(version);

        ClassOrInterfaceDeclaration versionClass = versionJava.getClassByName("Version").get();
        if (versionClass.getFieldByName(newFieldName).isPresent()) {
            LOGGER.lifecycle("New version constant [{}] already present, skipping", newFieldName);
            return Optional.empty();
        }

        NavigableMap<Version, FieldDeclaration> versions = versionClass.getFields()
            .stream()
            .map(f -> Map.entry(f, parseVersionField(f.getVariable(0).getNameAsString())))
            .filter(e -> e.getValue().isPresent())
            .collect(Collectors.toMap(e -> e.getValue().get(), Map.Entry::getKey, (v1, v2) -> {
                throw new IllegalArgumentException("Duplicate version constants " + v1);
            }, TreeMap::new));

        // find the version this should be inserted after
        var previousVersion = versions.lowerEntry(version);
        if (previousVersion == null) {
            throw new IllegalStateException(String.format("Could not find previous version to [%s]", version));
        }
        FieldDeclaration newVersion = createNewVersionConstant(
            previousVersion.getValue(),
            newFieldName,
            String.format("%d_%02d_%02d_99", version.getMajor(), version.getMinor(), version.getRevision())
        );
        versionClass.getMembers().addAfter(newVersion, previousVersion.getValue());

        if (updateCurrent) {
            versionClass.getFieldByName("CURRENT")
                .orElseThrow(() -> new IllegalArgumentException("Could not find CURRENT constant"))
                .getVariable(0)

View on GitHub (pinned to db6a809a66)

Solutions

  1. Open server/.../Version.java and find the two constants whose parsed version collides; remove or rename the erroneous one.
  2. Run parseVersionField logic mentally on each field name to spot the collision.
  3. Re-run updateVersions after fixing the source file.
Defensive patterns

Strategy: validation

Validate before calling

// Scan Version.java for duplicate parsed versions before running the task
Pattern VF = Pattern.compile("V_(\\d+)_(\\d+)_(\\d+)_(\\d+)");
Map<String, Long> counts = Files.readAllLines(versionJava)
    .stream().map(VF::matcher).filter(Matcher::find)
    .map(m -> m.group(1)+"."+m.group(2)+"."+m.group(3)+"("+m.group(4)+")")
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
Map<String,Long> dups = counts.entrySet().stream().filter(e -> e.getValue() > 1)
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
if (!dups.isEmpty()) throw new IllegalStateException("Duplicate version constants: " + dups);

Prevention

When it happens

Trigger: Version.java contains two field constants whose names parse via VERSION_FIELD to the same (major, minor, revision, qualifier). A merge in toMap then hits the collision merger.

Common situations: A botched merge introduced a duplicate version constant; a constant was renamed but the old one was not removed; the naming convention (V_X_YY_ZZ) collided for two qualifiers.

Related errors


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