quarkusio/quarkus · error · WebSocketException

Unable to inject @%s callback parameter '%s' declared on %s:

Error message

Unable to inject @%s callback parameter '%s' declared on %s: ambiguous injectors found: %s

What it means

When more than one parameter injector matches a callback parameter and the top two matches share the same priority, websockets-next cannot decide which to use and fails the build with an ambiguous-injectors WebSocketException. This prevents silently picking the wrong injector.

Source

Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/Callback.java:218

        }
        List<CallbackArgument> arguments = new ArrayList<>(parameters.size());
        for (MethodParameterInfo parameter : parameters) {
            List<CallbackArgument> found = callbackArguments
                    .findMatching(parameterContext(annotation, parameter, transformedAnnotations, index));
            if (found.isEmpty()) {
                String msg = String.format("Unable to inject @%s callback parameter '%s' declared on %s: no injector found",
                        DotNames.simpleName(annotation.name()),
                        parameter.name() != null ? parameter.name() : "#" + parameter.position(),
                        asString());
                throw new WebSocketException(msg);
            } else if (found.size() > 1 && (found.get(0).priority() == found.get(1).priority())) {
                String msg = String.format(
                        "Unable to inject @%s callback parameter '%s' declared on %s: ambiguous injectors found: %s",
                        DotNames.simpleName(annotation.name()),
                        parameter.name() != null ? parameter.name() : "#" + parameter.position(),
                        asString(),
                        found.stream().map(p -> p.getClass().getSimpleName() + ":" + p.priority()));
                throw new WebSocketException(msg);
            }
            arguments.add(found.get(0));
        }
        return List.copyOf(arguments);
    }

    Type argumentType(Predicate<CallbackArgument> filter) {
        for (int i = 0; i < arguments.size(); i++) {
            if (filter.test(arguments.get(i))) {
                return method.parameterType(i);
            }
        }
        return null;
    }

    private ParameterContext parameterContext(AnnotationInstance callbackAnnotation, MethodParameterInfo parameter,
            TransformedAnnotationsBuildItem transformedAnnotations, IndexView index) {
        return new ParameterContext() {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove or narrow your custom ParameterConverter so it does not overlap the built-in one (check its matches())
  2. Register your converter with a higher priority than the competing one so matching is deterministic
  3. Change the parameter annotation/type so only one converter matches
  4. Upgrade/downgrade websockets-next if a known bug causes overlapping built-in converters

Example fix

// before: custom converter competing with built-in at same priority
@Priority(1)
class MyParamConverter implements ParameterConverter { ... }
// after
@Priority(10)
class MyParamConverter implements ParameterConverter { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure custom ParameterConverter.matches() does not overlap built-ins:
// if (builtInMatches(param)) return false; in your converter

Prevention

When it happens

Trigger: A callback parameter whose annotation+type combination is matched by multiple registered ParameterConverters with equal priority — e.g. overlapping custom ParameterConverter registrations or built-in ambiguity between converters.

Common situations: Registering a custom ParameterConverter that also matches types already handled by built-in converters; two extensions or app classes each registering converters matching the same parameter; extension version combinations introducing overlapping converters.

Related errors


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