quarkusio/quarkus · error · IllegalArgumentException

Variant list must not be empty

Error message

Variant list must not be empty

What it means

RequestImpl.selectVariant() throws IllegalArgumentException because the JAX-RS contract requires a non-null, non-empty variant list when performing server-driven content negotiation. The library cannot negotiate against zero candidates.

Source

Thrown at independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/RequestImpl.java:42

    public RequestImpl(ResteasyReactiveRequestContext requestContext) {
        this.requestContext = requestContext;
        this.httpMethod = requestContext.serverRequest().getRequestMethod();
    }

    @Override
    public String getMethod() {
        return requestContext.serverRequest().getRequestMethod();
    }

    private boolean isRfc7232preconditions() {
        return true;//todo: do we need config for this?
    }

    @Override
    public Variant selectVariant(List<Variant> variants) throws IllegalArgumentException {
        if (variants == null || variants.size() == 0)
            throw new IllegalArgumentException("Variant list must not be empty");

        ServerDrivenNegotiation negotiation = new ServerDrivenNegotiation();
        MultivaluedMap<String, String> requestHeaders = requestContext.getHttpHeaders().getRequestHeaders();
        negotiation.setAcceptHeaders(requestHeaders.get(HttpHeaders.ACCEPT));
        negotiation.setAcceptCharsetHeaders(requestHeaders.get(HttpHeaders.ACCEPT_CHARSET));
        negotiation.setAcceptEncodingHeaders(requestHeaders.get(HttpHeaders.ACCEPT_ENCODING));
        negotiation.setAcceptLanguageHeaders(requestHeaders.get(HttpHeaders.ACCEPT_LANGUAGE));

        varyHeader = AbstractResponseBuilder.createVaryHeader(variants);
        requestContext.serverResponse().setResponseHeader(HttpHeaders.VARY, varyHeader);
        //response.getOutputHeaders().add(VARY, varyHeader);
        return negotiation.getBestMatch(variants);
    }

    private List<EntityTag> convertEtag(List<String> tags) {
        ArrayList<EntityTag> result = new ArrayList<EntityTag>();
        for (String tag : tags) {
            String[] split = tag.split(",");

View on GitHub (pinned to e1c734241f)

Solutions

  1. Populate the Variant list with at least one Variant before calling selectVariant().
  2. Guard the call: only invoke selectVariant when the list is non-empty, otherwise return a default representation or 406.
  3. Verify VariantListBuilder usage: addXXX(...) followed by add() actually appended the variants.

Example fix

// before
Variant v = request.selectVariant(variants);
// after
if (variants == null || variants.isEmpty()) {
    throw new NotAcceptableException();
}
Variant v = request.selectVariant(variants);
Defensive patterns

Strategy: validation

Validate before calling

if (variants == null || variants.isEmpty()) {
    throw new NotAcceptableException("No producible variants");
}

Type guard

boolean negotiable(List<Variant> v) {
    return v != null && !v.isEmpty();
}

Try / catch

try {
    return request.selectVariant(variants);
} catch (IllegalArgumentException e) {
    throw new NotAcceptableException(e.getMessage());
}

Prevention

When it happens

Trigger: Calling request.selectVariant(List<Variant>) with null or an empty list (e.g. Variant.encodings(...).build() produced no variants or a filter removed them all).

Common situations: Building variants from configuration or a database that returned no rows; passing a list built conditionally where every branch was skipped; API misuse where variants were intended to be added after the call.

Related errors


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