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
- Send valid authentication with the POST (basic auth header matching the elytron properties realm).
- Confirm quarkus.http.auth.permission policies cover POST requests for the mapped path and a realm is configured.
- Check @ServletSecurity constraints so container-managed auth runs before doPost.
- 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
- Design deletes as idempotent on the client (404 == success)
- Use ids captured in the same session, never stale cached ids
- Double-check tenant header before delete in multi-tenant tests
- Avoid double-delete in test cleanup; use @AfterEach with existence checks
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
- No producers for required item %s, step builder used: %s
- Build step '%s' does not produce any build item and thus wil
- Cannot consume/produce interface or abstract class build ite
- AuthenticationFailedException
- AuthenticationFailedException
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/27ab62ca7993dff4.
Report an issue: GitHub.