{"record":{"id":"9171abf18e7a58d5","repo":"quarkusio/quarkus","slug":"no-producers-for-required-item-s-step-builder-us","errorCode":null,"errorMessage":"No producers for required item %s, step builder used: %s","messagePattern":"No producers for required item (.+?), step builder used: (.+?)","errorType":"exception","errorClass":"ChainBuildException","httpStatus":null,"severity":"error","filePath":"core/builder/src/main/java/io/quarkus/builder/BuildChainBuilder.java","lineNumber":196,"sourceCode":"\n    private Map<BuildStepBuilder, Set<Produce>> wireDependencies(Set<BuildStepBuilder> included)\n            throws ChainBuildException {\n        Map<ItemId, List<Produce>> allProduces = extractProducers();\n        final ArrayDeque<BuildStepBuilder> toAdd = new ArrayDeque<>(); // the queue of steps to be added\n        for (ItemId finalId : finalIds) {\n            addItem(allProduces, included, toAdd, finalId);\n        }\n\n        // now recursively add producers of consumed items\n        Map<BuildStepBuilder, Set<Produce>> dependencies = new LinkedHashMap<>();\n        BuildStepBuilder stepBuilder;\n        while ((stepBuilder = toAdd.pollFirst()) != null) {\n            for (Map.Entry<ItemId, Consume> entry : stepBuilder.getConsumes().entrySet()) {\n                final Consume consume = entry.getValue();\n                final ItemId id = entry.getKey();\n                if (!consume.flags().contains(ConsumeFlag.OPTIONAL) && !id.isMulti()) {\n                    if (!initialIds.contains(id) && !allProduces.containsKey(id)) {\n                        throw new ChainBuildException(\n                                \"No producers for required item \" + id + \", step builder used: \" + stepBuilder);\n                    }\n                }\n                // add every producer\n                addItem(allProduces, included, toAdd, id,\n                        dependencies.computeIfAbsent(stepBuilder, x -> new LinkedHashSet<>()));\n            }\n        }\n        return dependencies;\n    }\n\n    private Map<ItemId, List<Produce>> extractProducers() throws ChainBuildException {\n        final Map<ItemId, List<Produce>> allProduces = new LinkedHashMap<>();\n        for (Map.Entry<BuildStepBuilder, StackTraceElement[]> stepEntry : steps.entrySet()) {\n            final BuildStepBuilder stepBuilder = stepEntry.getKey();\n            final Map<ItemId, Produce> stepProduces = stepBuilder.getProduces();\n            for (Map.Entry<ItemId, Produce> entry : stepProduces.entrySet()) {\n                final ItemId id = entry.getKey();","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/builder/src/main/java/io/quarkus/builder/BuildChainBuilder.java#L178-L214","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Send valid credentials with the request (e.g. basic auth user/password configured in application.properties for the elytron test realm).","Verify application.properties configures quarkus.http.auth.permission.* policies requiring authentication for /* and a working elytron identity mapping.","Check that @ServletSecurity or web.xml constraints require roles so Undertow/Elytron authenticates before doGet runs.","Guard the code: check req.getUserPrincipal() for null before calling getName()."],"exampleFix":"// before\nif (req.getUserPrincipal().getName() == null) {\n    throw new RuntimeException(\"principal was null\");\n}\n// after\nif (req.getUserPrincipal() == null) {\n    throw new RuntimeException(\"principal was null\");\n}","handlingStrategy":"validation","validationCode":"Response r = given().header(\"tenantId\", tenant).get(\"/fruits/\" + id);\nif (r.getStatusCode() == 404) {\n    throw new SkipException(\"Fruit \" + id + \" not present in tenant \" + tenant);\n}","typeGuard":null,"tryCatchPattern":"try {\n    given().header(\"tenantId\", tenant).body(fruit).put(\"/fruits/\" + id);\n} catch (WebApplicationException e) {\n    if (e.getResponse().getStatus() == 404) { /* recreate or skip */ }\n    else throw e;\n}","preventionTips":["Always send the correct tenant header for multi-tenant endpoints","Resolve ids from POST/GET responses instead of hard-coding them","Treat 404 on PUT as a state error and recreate the resource","Verify test seed data in the target tenant before update calls"],"tags":["servlet","security","elytron","authentication"],"backgroundTag":"unauthenticated-request-no-principal","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}