{"record":{"id":"f4eac972baef840a","repo":"quarkusio/quarkus","slug":"mapper-returned-null","errorCode":null,"errorMessage":"Mapper returned null","messagePattern":"Mapper returned null","errorType":"validation","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/RestMulti.java","lineNumber":318,"sourceCode":"             */\n            @Override\n            public void onSubscribe(Flow.Subscription subscription) {\n                if (secondUpstream.compareAndSet(null, subscription)) {\n                    long r = requested.getAndSet(0L);\n                    if (r != 0L) {\n                        subscription.request(r);\n                    }\n                }\n            }\n\n            @Override\n            public void onItem(I item) {\n                Multi<? extends O> publisher;\n\n                try {\n                    publisher = dataExtractor.apply(item);\n                    if (publisher == null) {\n                        throw new NullPointerException(MAPPER_RETURNED_NULL);\n                    }\n                    if (headersExtractor != null) {\n                        headers.set(headersExtractor.apply(item));\n                    }\n                    if (statusExtractor != null) {\n                        status.set(statusExtractor.apply(item));\n                    }\n                } catch (Throwable ex) {\n                    downstream.onError(ex);\n                    return;\n                }\n\n                publisher.subscribe(this);\n            }\n\n            @Override\n            public void onFailure(Throwable failure) {\n                downstream.onError(failure);","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/RestMulti.java#L300-L336","documentation":"When streaming a Multi of items, RestMulti uses the `dataExtractor` function to map each item to the Multi/actual data to emit. If the mapper returns null the framework cannot represent the item and signals a NullPointerException with the 'Mapper returned null' message, per reactive-streams rules that onNext values must be non-null.","triggerScenarios":"Using `RestMulti.fromMulti(multi, dataExtractor, ...)` where `dataExtractor.apply(item)` returns null for any emitted item — e.g. a mapper that unwraps an Optional, looks up a field that is absent, or returns null for a sentinel element.","commonSituations":"Mapping DTOs where an optional field is missing; `map.get(key)` returning null for a missing key; extracting from records/entities where a nullable column is null; mapper logic returning null as a 'skip' signal instead of filtering.","solutions":["Return a non-null value from the mapper — e.g. return an empty collection/instance or use `Optional.orElse(...)` before extracting.","Filter out items that would map to null before the RestMulti stage: `multi.filter(i -> extract(i) != null)`.","Fix the mapper logic so nulls (missing keys, empty optionals) are handled explicitly instead of propagated."],"exampleFix":"// before\nRestMulti.fromMulti(multi, item -> item.getPayload(), null, null).build(); // getPayload() may be null\n// after\nRestMulti.fromMulti(multi,\n    item -> java.util.Objects.requireNonNullElse(item.getPayload(), Payload.empty()),\n    null, null).build();","handlingStrategy":"validation","validationCode":"multi = multi.filter(item -> extractData(item) != null);","typeGuard":"boolean isExtractable(Item item) {\n    return item != null && item.getPayload() != null;\n}","tryCatchPattern":"try {\n    return RestMulti.fromMulti(multi, dataExtractor, null, null).build();\n} catch (NullPointerException e) {\n    LOG.error(\"Data extractor returned null\", e);\n    throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);\n}","preventionTips":["Make dataExtractor total: return an empty value instead of null for missing data.","Use Objects.requireNonNullElse or Optional.orElse inside mappers.","Filter nullable items upstream before the RestMulti stage."],"tags":["null-pointer","mapper","reactive-streams","resteasy-reactive"],"backgroundTag":"mapper-returned-null","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}