{"record":{"id":"e7c64af1a791bf81","repo":"quarkusio/quarkus","slug":"function-for-trigger-trigger-has-multiple-mat","errorCode":null,"errorMessage":"Function for trigger '${trigger}' has multiple matching invokers","messagePattern":"Function for trigger '(.+?)' has multiple matching invokers","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/funqy/funqy-knative-events/runtime/src/main/java/io/quarkus/funqy/runtime/bindings/knative/events/KnativeEventsBindingRecorder.java","lineNumber":106,"sourceCode":"                    trigger = annotation.trigger();\n                } else {\n                    trigger = invoker.getName();\n                }\n                filter = filter(invoker.getName(), annotation);\n            } else {\n                trigger = invoker.getName();\n                filter = Collections.emptyList();\n            }\n            invokersFilters.put(invoker.getName(), filter);\n            typeTriggers.compute(trigger, (k, v) -> {\n                if (v == null) {\n                    v = new ArrayList<>();\n                }\n                // validate if there are no conflicts for the same type (trigger) and defined filters\n                // as resolution based on trigger (ce-type) and optional filters (on ce-attributes) can return only\n                // one function invoker\n                if (v.stream().anyMatch(i -> hasSameFilters(i.getName(), invokersFilters.get(i.getName()), filter))) {\n                    throw new IllegalStateException(\"Function for trigger '\" + trigger + \"' has multiple matching invokers\");\n                }\n\n                v.add(invoker);\n                return v;\n            });\n\n            if (invoker.hasInput()) {\n                Type inputType = invoker.getInputType();\n\n                if (CloudEvent.class.equals(Reflections.getRawType(inputType))) {\n                    if (inputType instanceof ParameterizedType) {\n                        Type[] params = ((ParameterizedType) inputType).getActualTypeArguments();\n                        if (params.length == 1) {\n                            inputType = params[0];\n                            invoker.getBindingContext().put(INPUT_CE_DATA_TYPE, inputType);\n                        }\n                    } else {\n                        throw new RuntimeException(\"When using CloudEvent<> generic parameter must be used.\");","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/funqy/funqy-knative-events/runtime/src/main/java/io/quarkus/funqy/runtime/bindings/knative/events/KnativeEventsBindingRecorder.java#L88-L124","documentation":"KnativeEventsBindingRecorder.init registers invokers keyed by trigger (ce-type) plus optional attribute filters. If two invokers for the same trigger have overlapping filters so a single incoming event could match more than one function, registration fails with IllegalStateException to prevent ambiguous dispatch.","triggerScenarios":"Two Funqy functions annotated with the same Knative trigger ce-type and identical/overlapping ce-attribute filters are registered during staticInit; hasSameFilters finds a conflict and init throws.","commonSituations":"Copy-pasting a @Function with the same @OnTrigger/@OnEvent type and filters; two deployments of the same function class; same ce-type intentionally used with filters that end up identical instead of disjoint.","solutions":["Remove or rename the duplicate function's trigger type so each trigger maps to one invoker.","Differentiate the functions' ce-attribute filters so they are mutually exclusive.","Ensure only one bean exposes a given trigger; delete the stale duplicate class.","Use quarkus.funqy.export to select a single function if multiple must exist in code."],"exampleFix":"// before\n@OnTrigger(type = \"com.example.created\") public void f1(String s) {}\n@OnTrigger(type = \"com.example.created\") public void f2(String s) {}\n// after\n@OnTrigger(type = \"com.example.created\") public void f1(String s) {}\n@OnTrigger(type = \"com.example.updated\") public void f2(String s) {}","handlingStrategy":"validation","validationCode":"// At startup, verify no two functions share the same trigger type\nMap<String, Long> counts = functions.stream()\n    .collect(Collectors.groupingBy(f -> f.triggerType(), Collectors.counting()));\nList<String> dupes = counts.entrySet().stream().filter(e -> e.getValue() > 1).map(Map.Entry::getKey).toList();\nif (!dupes.isEmpty()) throw new IllegalStateException(\"Duplicate triggers: \" + dupes);","typeGuard":"boolean triggerIsUnique(String trigger, List<FunctionDef> all, FunctionDef self) {\n    return all.stream().filter(f -> f.triggerType().equals(trigger)).count() == 1;\n}","tryCatchPattern":"try { app.start(); } catch (IllegalStateException e) { if (e.getMessage().contains(\"multiple matching invokers\")) { log.error(\"Duplicate trigger/filters on functions - disambiguate ce-type or filters\", e); } throw e; }","preventionTips":["Keep one function per ce-type","Make attribute filters mutually exclusive when sharing a type","Name triggers with a naming convention to avoid collisions","Review @OnTrigger/@Function annotations after copy-paste refactors"],"tags":["knative","cloudevent","ambiguous-dispatch","funqy","duplicate-mapping"],"backgroundTag":"ambiguous-function-mapping","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}