quarkusio/quarkus · error · ChainBuildException

No producers for required item %s, step builder used: %s

Error message

No producers for required item %s, step builder used: %s

What it means

This integration-test servlet throws RuntimeException("principal was null") in doGet when the security check on the principal name fails. Despite the message, the code actually calls req.getUserPrincipal().getName() — a NullPointerException occurs here if getUserPrincipal() returns null (unauthenticated request). It signals that the request reached the servlet without an authenticated principal, i.e. Elytron security did not authenticate/propagate the identity as the test expects.

Source

Thrown at core/builder/src/main/java/io/quarkus/builder/BuildChainBuilder.java:196

    private Map<BuildStepBuilder, Set<Produce>> wireDependencies(Set<BuildStepBuilder> included)
            throws ChainBuildException {
        Map<ItemId, List<Produce>> allProduces = extractProducers();
        final ArrayDeque<BuildStepBuilder> toAdd = new ArrayDeque<>(); // the queue of steps to be added
        for (ItemId finalId : finalIds) {
            addItem(allProduces, included, toAdd, finalId);
        }

        // now recursively add producers of consumed items
        Map<BuildStepBuilder, Set<Produce>> dependencies = new LinkedHashMap<>();
        BuildStepBuilder stepBuilder;
        while ((stepBuilder = toAdd.pollFirst()) != null) {
            for (Map.Entry<ItemId, Consume> entry : stepBuilder.getConsumes().entrySet()) {
                final Consume consume = entry.getValue();
                final ItemId id = entry.getKey();
                if (!consume.flags().contains(ConsumeFlag.OPTIONAL) && !id.isMulti()) {
                    if (!initialIds.contains(id) && !allProduces.containsKey(id)) {
                        throw new ChainBuildException(
                                "No producers for required item " + id + ", step builder used: " + stepBuilder);
                    }
                }
                // add every producer
                addItem(allProduces, included, toAdd, id,
                        dependencies.computeIfAbsent(stepBuilder, x -> new LinkedHashSet<>()));
            }
        }
        return dependencies;
    }

    private Map<ItemId, List<Produce>> extractProducers() throws ChainBuildException {
        final Map<ItemId, List<Produce>> allProduces = new LinkedHashMap<>();
        for (Map.Entry<BuildStepBuilder, StackTraceElement[]> stepEntry : steps.entrySet()) {
            final BuildStepBuilder stepBuilder = stepEntry.getKey();
            final Map<ItemId, Produce> stepProduces = stepBuilder.getProduces();
            for (Map.Entry<ItemId, Produce> entry : stepProduces.entrySet()) {
                final ItemId id = entry.getKey();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Send valid credentials with the request (e.g. basic auth user/password configured in application.properties for the elytron test realm).
  2. Verify application.properties configures quarkus.http.auth.permission.* policies requiring authentication for /* and a working elytron identity mapping.
  3. Check that @ServletSecurity or web.xml constraints require roles so Undertow/Elytron authenticates before doGet runs.
  4. Guard the code: check req.getUserPrincipal() for null before calling getName().

Example fix

// before
if (req.getUserPrincipal().getName() == null) {
    throw new RuntimeException("principal was null");
}
// after
if (req.getUserPrincipal() == null) {
    throw new RuntimeException("principal was null");
}
Defensive patterns

Strategy: validation

Validate before calling

Response r = given().header("tenantId", tenant).get("/fruits/" + id);
if (r.getStatusCode() == 404) {
    throw new SkipException("Fruit " + id + " not present in tenant " + tenant);
}

Try / catch

try {
    given().header("tenantId", tenant).body(fruit).put("/fruits/" + id);
} catch (WebApplicationException e) {
    if (e.getResponse().getStatus() == 404) { /* recreate or skip */ }
    else throw e;
}

Prevention

When it happens

Trigger: An unauthenticated GET request reaches /* in the elytron-undertow integration test: the security domain/auth mechanism did not run or failed, so getUserPrincipal() is null and .getName() throws; or a principal whose getName() returns null is attached.

Common situations: Missing or wrong Authorization header/basic-auth credentials in the test request; quarkus.http.auth.* permission config allowing the path anonymously when it should require a role; elytron properties-file identity config missing so no user is authenticated; calling the endpoint through a proxy/filter that strips security context.

Related errors


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