quarkusio/quarkus · error · ChainBuildException

cycle detection failure report (dynamic CycleBuildException

Error message

cycle detection failure report (dynamic CycleBuildException message listing dependency cycle)

What it means

Same check as doGet but in doPost of GreetingServlet: the servlet asserts an authenticated principal exists before echoing the POST body. If Elytron did not authenticate the request, getUserPrincipal() is null and getName() throws NPE, surfacing as this error. It indicates the POST bypassed or failed authentication.

Source

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

            if (!visited.add(builder)) {
                final StringBuilder b = new StringBuilder("Cycle detected:\n\t\t   ");
                final Iterator<Produce> itr = producedPath.descendingIterator();
                if (itr.hasNext()) {
                    Produce produce = itr.next();
                    for (;;) {
                        b.append(produce.getStepBuilder().getBuildStep());
                        ItemId itemId = produce.getItemId();
                        b.append(" produced ").append(itemId);
                        b.append("\n\t\tto ");
                        if (!itr.hasNext())
                            break;
                        produce = itr.next();
                        if (produce.getStepBuilder() == builder)
                            break;
                    }
                    b.append(builder.getBuildStep());
                }
                throw new ChainBuildException(b.toString());
            }
            try {
                final Set<Produce> dependencySet = dependencies.getOrDefault(builder, Collections.emptySet());
                cycleCheckProduce(dependencySet, visited, checked, dependencies, producedPath);
            } finally {
                visited.remove(builder);
            }
        }
        checked.add(builder);
    }

    private void addItem(final Map<ItemId, List<Produce>> allProduces, final Set<BuildStepBuilder> included,
            final ArrayDeque<BuildStepBuilder> toAdd, final ItemId idToAdd) {
        addItem(allProduces, included, toAdd, idToAdd, null);
    }

    private void addItem(final Map<ItemId, List<Produce>> allProduces, final Set<BuildStepBuilder> included,
            final ArrayDeque<BuildStepBuilder> toAdd, final ItemId idToAdd, final Set<Produce> dependencies) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Send valid authentication with the POST (basic auth header matching the elytron properties realm).
  2. Confirm quarkus.http.auth.permission policies cover POST requests for the mapped path and a realm is configured.
  3. Check @ServletSecurity constraints so container-managed auth runs before doPost.
  4. Null-check getUserPrincipal() before invoking 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: try-catch

Validate before calling

boolean exists = given().header("tenantId", tenant).get("/fruits/" + id).getStatusCode() == 200;
if (!exists) return; // nothing to delete

Try / catch

Response r = given().header("tenantId", tenant).delete("/fruits/" + id);
if (r.getStatusCode() == 404) {
    // idempotent delete: already gone, acceptable
} else {
    r.then().statusCode(204);
}

Prevention

When it happens

Trigger: POST to /* without valid credentials or when the auth mechanism fails, so req.getUserPrincipal() is null and .getName() throws; or a null-name principal is installed.

Common situations: Test client forgetting to send basic-auth credentials on POST; security policy permitting POST anonymously; elytron realm not configured so no identities exist; session expired between GET and POST.

Related errors


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