quarkusio/quarkus · error · IllegalArgumentException

Predicate already set

Error message

Predicate already set

What it means

The HotDeploymentWatchedFileBuildItem.Builder allows exactly one of location or predicate. Once a predicate has been set, calling setLocation would silently create an ambiguous watcher, so the builder throws IllegalArgumentException 'Predicate already set'.

Source

Thrown at core/deployment/src/main/java/io/quarkus/deployment/builditem/HotDeploymentWatchedFileBuildItem.java:104

    }

    /**
     *
     * @return {@code true} if a file change should result in an application restart, {@code false} otherwise
     */
    public boolean isRestartNeeded() {
        return restartNeeded;
    }

    public static class Builder {

        private String location;
        private Predicate<String> locationPredicate;
        private boolean restartNeeded = true;

        public Builder setLocation(String location) {
            if (locationPredicate != null) {
                throw new IllegalArgumentException("Predicate already set");
            }
            this.location = location;
            return this;
        }

        public Builder setLocationPredicate(Predicate<String> locationPredicate) {
            if (location != null) {
                throw new IllegalArgumentException("Location already set");
            }
            this.locationPredicate = locationPredicate;
            return this;
        }

        public Builder setRestartNeeded(boolean restartNeeded) {
            this.restartNeeded = restartNeeded;
            return this;
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Choose one mechanism: if you need string matching, use setLocation and drop setLocationPredicate (and vice versa).
  2. Use a fresh Builder instance per watch entry instead of reusing/reconfiguring one.
  3. If you must support both, convert the location check into a predicate: p -> p.equals(location) and set only the predicate.

Example fix

// before
HotDeploymentWatchedFileBuildItem item = HotDeploymentWatchedFileBuildItem.builder()
        .setLocationPredicate(p -> p.startsWith("config/"))
        .setLocation("config/app.yaml")
        .build();
// after
HotDeploymentWatchedFileBuildItem item = HotDeploymentWatchedFileBuildItem.builder()
        .setLocationPredicate(p -> p.startsWith("config/"))
        .build();
Defensive patterns

Strategy: validation

Validate before calling

HotDeploymentWatchedFileBuildItem.Builder b = HotDeploymentWatchedFileBuildItem.builder();
if (location != null) {
    b.setLocation(location);
} else if (predicate != null) {
    b.setLocationPredicate(predicate);
} else {
    return; // nothing to watch
}

Try / catch

try {
    return builder.setLocation(location).build();
} catch (IllegalArgumentException e) {
    if ("Predicate already set".equals(e.getMessage())) {
        return HotDeploymentWatchedFileBuildItem.builder().setLocation(location).build();
    }
    throw e;
}

Prevention

When it happens

Trigger: Chaining builder calls where setLocationPredicate(...) is invoked before setLocation(...), or calling both setters on the same Builder instance.

Common situations: Code paths that merge defaults (predicate) with user config (location) on the same builder; copy-pasted builder chains where the wrong setter was left in.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/8c644d1c29971d75. Report an issue: GitHub.