quarkusio/quarkus · error · IllegalArgumentException

Uni must be used with type parameter (e.g. Uni<String>).

Error message

Uni must be used with type parameter (e.g. Uni<String>).

What it means

Funqy supports reactive functions returning Mutiny Uni. The FunctionInvoker constructor inspects the generic return type to determine the output type. A raw Uni (no type parameter, e.g. method returns plain Uni) gives no output type, so an IllegalArgumentException is thrown at startup.

Source

Thrown at extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionInvoker.java:57

                }
                parameterInjectors.add(injector);
            }
        }
        constructor = new FunctionConstructor(targetClass);
        Class<?> returnType = method.getReturnType();
        if (returnType != null) {
            if (Uni.class.isAssignableFrom(returnType)) {
                outputType = null;
                isAsync = true;
                Type genericReturnType = method.getGenericReturnType();
                if (genericReturnType instanceof ParameterizedType) {
                    Type[] actualParams = ((ParameterizedType) genericReturnType).getActualTypeArguments();
                    if (actualParams.length == 1) {
                        outputType = actualParams[0];
                    }
                }
                if (outputType == null) {
                    throw new IllegalArgumentException(
                            "Uni must be used with type parameter (e.g. Uni<String>).");
                }
            } else {
                outputType = method.getGenericReturnType();
            }
        }
    }

    /**
     * Allow storage of binding specific objects that are specific to the function.
     * i.e. json marshallers
     *
     * @return
     */
    public Map<String, Object> getBindingContext() {
        return bindingContext;
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add an explicit type parameter to the Uni return type
  2. If the value is dynamic, use Uni<Object> or a concrete domain type
  3. Rebuild; the check runs when the invoker is constructed at startup

Example fix

// before
@Funq public Uni getData() { ... }
// after
@Funq public Uni<String> getData() { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify Uni return types are parameterized before startup
static void assertParameterizedUni(Method m) {
    Type rt = m.getGenericReturnType();
    if (rt instanceof Class && Uni.class.isAssignableFrom((Class<?>) rt))
        throw new IllegalArgumentException(m + " must return Uni<T> with a type parameter");
}

Type guard

static boolean isParameterizedUni(Type returnType) {
    return returnType instanceof ParameterizedType
        && ((ParameterizedType) returnType).getRawType() == Uni.class;
}

Try / catch

try {
    registry.register(...);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Uni must be used with type parameter"))
        log.errorf("Fix return type to Uni<T>, method: %s", e.getMessage());
    throw e;
}

Prevention

When it happens

Trigger: Declaring @Funq public Uni noTypeParam() { ... } — returning Uni without a generic parameter such as Uni<String>.

Common situations: Writing a reactive function quickly and forgetting the generic; IDEs generating raw Uni when refactoring from CompletionStage; type erasure surprises when returning Uni.fromFuture(...).

Related errors


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