{"record":{"id":"de197a0c09d3ae6a","repo":"elastic/elasticsearch","slug":"release-s-already-recorded-with-version-id-s","errorCode":null,"errorMessage":"Release [%s] already recorded with version id [%s], cannot update to version [%s]","messagePattern":"Release \\[(.+?)\\] already recorded with version id \\[(.+?)\\], cannot update to version \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/TagVersionsTask.java","lineNumber":115,"sourceCode":"        return Map.of(INDEX_VERSION_TYPE, v7Version);\n    }\n\n    private static final Pattern VERSION_LINE = Pattern.compile(\"(\\\\d+\\\\.\\\\d+\\\\.\\\\d+),(\\\\d+)\");\n\n    static Optional<List<String>> addVersionRecord(List<String> versionRecordLines, Version release, int id) {\n        Map<Version, Integer> versions = versionRecordLines.stream().map(l -> {\n            Matcher m = VERSION_LINE.matcher(l);\n            if (m.matches() == false) throw new IllegalArgumentException(String.format(\"Incorrect format for line [%s]\", l));\n            return m;\n        }).collect(Collectors.toMap(m -> Version.fromString(m.group(1)), m -> Integer.parseInt(m.group(2))));\n\n        Integer existing = versions.putIfAbsent(release, id);\n        if (existing != null) {\n            if (existing.equals(id)) {\n                LOGGER.lifecycle(\"Version id [{}] for release [{}] already recorded\", id, release);\n                return Optional.empty();\n            } else {\n                throw new IllegalArgumentException(\n                    String.format(\n                        \"Release [%s] already recorded with version id [%s], cannot update to version [%s]\",\n                        release,\n                        existing,\n                        id\n                    )\n                );\n            }\n        }\n\n        return Optional.of(\n            versions.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(e -> e.getKey() + \",\" + e.getValue()).toList()\n        );\n    }\n}\n","sourceCodeStart":97,"sourceCodeEnd":131,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/TagVersionsTask.java#L97-L131","documentation":"Thrown in TagVersionsTask.addVersionRecord() when the release version is already present in the record file but with a DIFFERENT id than the one being written. An identical id is a no-op (returns Optional.empty() with a lifecycle log); a conflicting id is rejected to keep the version→id mapping authoritative.","triggerScenarios":"Re-running tagVersions for an already-released version with a new --tag-version id, e.g. the release was first tagged Index:42 and is now being tagged Index:43.","commonSituations":"A release engineer mistakenly re-tags; the id space was renumbered; the same version is being processed by two concurrent release runs.","solutions":["Confirm the intended id matches the one already recorded for that release; if so, no action is needed (it is idempotent).","If the id genuinely must change, manually correct the record file under supervision and re-run, recording the change in the release audit log.","Prevent re-running tagVersions for an already-released version in the release automation."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Check whether the release is already recorded before tagging\nstatic boolean alreadyRecorded(Path recordFile, Version release) throws IOException {\n    return Files.readAllLines(recordFile).stream()\n        .map(l -> l.split(\",\"))\n        .anyMatch(p -> Version.fromString(p[0]).equals(release));\n}\n// skip tagging if alreadyRecorded(...) returns true","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make the release step idempotent: check the record file before tagging.","Lock the release run so only one invocation can write the record at a time."],"tags":["release-tooling","version-record","conflict","data-integrity"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}