quarkusio/quarkus · error · WebSocketException

@OnError callback must accept exactly one error parameter; f

Error message

@OnError callback must accept exactly one error parameter; found %s: %s

What it means

Every @OnError callback must accept exactly one parameter recognized as the error (a Throwable subtype). If the callback has zero error parameters or more than one, the build fails, reporting how many were found and the callback signature.

Source

Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java:1859

                    throw new WebSocketException("@OnError callback on @WebSocketClient must not accept WebSocketConnection: "
                            + method.declaringClass() + "." + method.name() + "()");
                }
            } else if (method.parameterTypes().stream().map(Type::name)
                    .anyMatch(WebSocketDotNames.WEB_SOCKET_CLIENT_CONNECTION::equals)) {
                target = Target.CLIENT;
                if (expectedTarget == Target.SERVER) {
                    throw new WebSocketException("@OnError callback on @WebSocket must not accept WebSocketClientConnection: "
                            + method.declaringClass() + "." + method.name() + "()");
                }
            } else {
                target = Target.UNDEFINED;
            }
            Callback callback = new Callback(target, annotation, bean, method,
                    executionModel(method, transformedAnnotations), callbackArguments, transformedAnnotations,
                    endpointPath, index);
            long errorArguments = callback.arguments.stream().filter(ca -> ca instanceof ErrorCallbackArgument).count();
            if (errorArguments != 1) {
                throw new WebSocketException(
                        String.format("@OnError callback must accept exactly one error parameter; found %s: %s",
                                errorArguments, callback.asString()));
            }
            errorHandlers.add(callback);
        }
        return errorHandlers;
    }

    private static List<AnnotationInstance> findCallbackAnnotations(IndexView index, ClassInfo beanClass,
            DotName annotationName) {
        ClassInfo clazz = beanClass;
        List<AnnotationInstance> annotations = new ArrayList<>();
        while (clazz != null) {
            List<AnnotationInstance> declared = clazz.annotationsMap().get(annotationName);
            if (declared != null) {
                annotations.addAll(declared);
            }
            DotName superName = clazz.superName();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add exactly one parameter that is a Throwable (or subclass) type
  2. Remove any extra Throwable parameters; inspect the cause via getCause() instead
  3. Verify the parameter type extends java.lang.Throwable so it is recognized as the error argument

Example fix

// before
@OnError
void onError(WebSocketConnection conn) {}

// after
@OnError
void onError(WebSocketConnection conn, Exception e) {}
Defensive patterns

Strategy: validation

Validate before calling

for (Method m : MyWebSocket.class.getDeclaredMethods()) {
    if (m.isAnnotationPresent(OnError.class)) {
        long n = Arrays.stream(m.getParameterTypes()).filter(Throwable.class::isAssignableFrom).count();
        if (n != 1) throw new IllegalStateException(m + " must accept exactly one Throwable parameter");
    }
}

Type guard

static boolean hasSingleErrorParam(Method m) {
    return Arrays.stream(m.getParameterTypes())
        .filter(Throwable.class::isAssignableFrom).count() == 1;
}

Prevention

When it happens

Trigger: @OnError method with no Throwable parameter (only a connection or message parameter); @OnError method listing two Throwable parameters; error parameter not recognized as an error argument by ErrorCallbackArgument::isError (e.g. not a Throwable subtype).

Common situations: Developer writes an @OnError that only logs the connection state and forgets the exception parameter; two Throwable parameters added for cause+exception; parameter typed as Object or String instead of Throwable.

Related errors


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