quarkusio/quarkus · error · IllegalArgumentException

${what} must not be null

Error message

${what} must not be null

What it means

The private CORS.Builder.merge(Optional<List<String>>, Set<String>, String) helper throws IllegalArgumentException(what + " must not be null") when the replacement Set passed to exposedHeaders/headers/methods/origins is null. The setters replace the accumulated list, so a null set has no valid meaning.

Source

Thrown at extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/security/CORS.java:202

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

        /**
         * Create a new CORS configuration.
         *
         * @return CORS instance, which should be passed to the {@link HttpSecurity} event
         */
        public CORS build() {
            return new CORSImpl(accessControlAllowCredentials, accessControlMaxAge, exposedHeaders, headers, methods, origins,
                    returnExactOrigins, varyOrigin);
        }

        private static Optional<List<String>> merge(Optional<List<String>> optionalOriginalList, Set<String> newSet,
                String what) {
            if (newSet == null) {
                throw new IllegalArgumentException(what + " must not be null");
            }
            if (newSet.isEmpty()) {
                return optionalOriginalList;
            }
            final List<String> result;
            if (optionalOriginalList.orElse(List.of()).isEmpty()) {
                result = List.copyOf(newSet);
            } else {
                result = Stream.concat(optionalOriginalList.get().stream(), newSet.stream()).toList();
            }
            return Optional.of(result);
        }

        record CORSImpl(Optional<Boolean> accessControlAllowCredentials, Optional<Duration> accessControlMaxAge,
                Optional<List<String>> exposedHeaders, Optional<List<String>> headers,
                Optional<List<String>> methods, Optional<List<String>> origins,
                boolean returnExactOrigins, boolean varyOrigin) implements CORS, CORSConfig {
            @Override

View on GitHub (pinned to e1c734241f)

Solutions

  1. Pass a non-null Set (use Set.of() or Collections.emptySet() if intentionally empty — empty sets are treated as no-op)
  2. Default null collections to an empty set before the call
  3. Fix the collection source to return an empty collection instead of null

Example fix

// before
Set<String> origins = configMap.get("origins");
builder.origins(origins);
// after
builder.origins(configMap.getOrDefault("origins", Set.of()));
Defensive patterns

Strategy: validation

Validate before calling

builder.origins(set == null ? Set.of() : set);

Type guard

static <T> Set<T> orEmpty(Set<T> s) { return s == null ? Set.of() : s; }

Prevention

When it happens

Trigger: Calling CORS.builder().exposedHeaders(null), headers(null), methods(null) or origins(null) — usually with a set produced by a nullable collection-returning call.

Common situations: Config collections that resolve to null; passing a Map.get result directly; refactoring where a Set field was never initialized.

Related errors


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