elastic/elasticsearch · error · InvalidUserDataException

At least one of add-branch, remove-branch or update-branch m

Error message

At least one of add-branch, remove-branch or update-branch must be specified

What it means

Thrown by UpdateBranchesJsonTask.executeTask() when none of addBranch, removeBranch, or updateBranch has been set. The task is a no-op without at least one operation, so it refuses to run.

Source

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

    @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);
        }
        if (removeBranch != null) {
            LOGGER.info("Removing branch {}", removeBranch);
            if (developmentBranches.stream().noneMatch(developmentBranch -> developmentBranch.name().equals(removeBranch))) {
                throw new InvalidUserDataException("Branch " + removeBranch + " does not exist");
            }
            developmentBranches.removeIf(developmentBranch -> developmentBranch.name().equals(removeBranch));
        }
        if (updateBranch != null) {
            LOGGER.info("Updating branch {} with version {}", updateBranch.name(), updateBranch.version());

View on GitHub (pinned to db6a809a66)

Solutions

  1. Provide at least one of --add-branch=<branch>:<version>, --remove-branch=<branch>, or --update-branch=<branch>:<version>.
  2. Audit the release script to confirm the conditional that supplies these options is reachable.

Example fix

// before
./gradlew updateBranches

// after
./gradlew updateBranches --add-branch=8.11:8.11.0
Defensive patterns

Strategy: validation

Validate before calling

// Fail early if no operation flag is present
tasks.named('updateBranches').configure(t -> t.doFirst(spec -> {
    var p = spec.getProviders();
    if (p.gradleProperty("add-branch").forUseAtConfigurationTime().isPresent()
        || p.gradleProperty("remove-branch").forUseAtConfigurationTime().isPresent()
        || p.gradleProperty("update-branch").forUseAtConfigurationTime().isPresent()) {
        return;
    }
    throw new GradleException("At least one of --add-branch, --remove-branch, --update-branch is required");
}));

Prevention

When it happens

Trigger: Invoking updateBranches without any of --add-branch, --remove-branch, or --update-branch.

Common situations: A release script conditionally builds the option list and supplied none; the options were renamed or mis-flagged.

Related errors


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