elastic/elasticsearch · error · InvalidUserDataException

Expected branch and version in format <branch>:<version>

Error message

Expected branch and version in format <branch>:<version>

What it means

Thrown by UpdateBranchesJsonTask.toDevelopmentBranch() when the --update-branch argument, split on ':', does not yield exactly two parts. The argument must be <branch>:<version>.

Source

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

    @Option(option = "add-branch", description = "Specifies the branch and corresponding version to add in format <branch>:<version>")
    public void addBranch(String branchAndVersion) {
        this.addBranch = toDevelopmentBranch(branchAndVersion);
    }

    @Option(option = "remove-branch", description = "Specifies the branch to remove")
    public void removeBranch(String branch) {
        this.removeBranch = branch;
    }

    @Option(option = "update-branch", description = "Specifies the branch and corresponding version to update in format <branch>:<version>")
    public void updateBranch(String branchAndVersion) {
        this.updateBranch = toDevelopmentBranch(branchAndVersion);
    }

    private DevelopmentBranch toDevelopmentBranch(String branchAndVersion) {
        String[] parts = branchAndVersion.split(":");
        if (parts.length != 2) {
            throw new InvalidUserDataException("Expected branch and version in format <branch>:<version>");
        }
        return new DevelopmentBranch(parts[0], Version.fromString(parts[1]));
    }

    @TaskAction
    public void executeTask() throws IOException {
        List<DevelopmentBranch> developmentBranches = readBranches(branchesFile);

        if (addBranch == null && removeBranch == null && updateBranch == null) {
            throw new InvalidUserDataException("At least one of add-branch, remove-branch or update-branch must be specified");
        }

        if (addBranch != null) {
            LOGGER.info("Adding branch {} with version {}", addBranch.name(), addBranch.version());
            if (developmentBranches.stream().anyMatch(developmentBranch -> developmentBranch.name().equals(addBranch.name()))) {
                throw new InvalidUserDataException("Branch " + addBranch.name() + " already exists");
            }
            developmentBranches.add(addBranch);

View on GitHub (pinned to db6a809a66)

Solutions

  1. Pass exactly two colon-separated tokens, e.g. --update-branch=8.10:8.10.0.
  2. Ensure neither the branch name nor the version legitimately contains a colon; if a version ever did, the splitter would need updating.
  3. Quote the argument so the shell does not interpret the colon.

Example fix

// before
./gradlew updateBranches --update-branch=8.10

// after
./gradlew updateBranches --update-branch=8.10:8.10.0
Defensive patterns

Strategy: validation

Validate before calling

// Validate the --update-branch token shape before invoking the task
static String normalizeBranchArg(String arg) {
    String[] parts = arg.split(":");
    if (parts.length != 2 || parts[0].isBlank() || parts[1].isBlank()) {
        throw new IllegalArgumentException("Expected <branch>:<version>, got " + arg);
    }
    return arg;
}

Prevention

When it happens

Trigger: Passing --update-branch with no colon, more than one colon, or an empty string; a version containing a colon would also push the part count past 2.

Common situations: Shell quoting swallowed the colon; a template variable produced an empty value; the branch or version string itself contains a colon.

Related errors


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