spring-projects/spring-ai · error · IllegalArgumentException

Type must be a Function, BiFunction, Function1 or…

Error message

Type must be a Function, BiFunction, Function1 or Function2. Found: 

What it means

Thrown when Spring AI tries to infer the input/output types of a functional bean but the bean's type is not a supported functional shape (Function, BiFunction, Kotlin Function1/Function2, or Supplier variants). The resolved generic type came back as ResolvableType.NONE.

Solutions

  1. Change the bean to implement java.util.function.Function<I,O> (or BiFunction / Kotlin Function1/Function2)
  2. Wrap unsupported types with an adapter lambda typed as Function
  3. Give the lambda an explicit target type (Function<Input, Output> f = in -> ...) rather than var/Object
  4. Specify the tool's input/output types explicitly instead of relying on type inference

Example fix

// before
@Bean
public TriFunction<String, String, String, String> myTool() { ... }
// after
@Bean
public Function<MyRequest, String> myTool() {
    return req -> doWork(req.a(), req.b());
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(bean instanceof Function) && !(bean instanceof BiFunction) && !(bean instanceof Supplier)) {
    throw new IllegalStateException(beanName + " must be a Function/BiFunction/Supplier to be exposed as a tool");
}

Type guard

boolean isFunctionalTool(Object bean) {
    return bean instanceof Function<?, ?> || bean instanceof BiFunction<?, ?, ?> || bean instanceof Supplier<?>;
}

Prevention

When it happens

Trigger: Registering a bean whose type implements none of Function/BiFunction/Consumer-type contracts (e.g. a custom interface, a 3-arg function, or a lambda typed only as Object) and then exposing it as a tool via FunctionToolCallback or ToolCallbacks.from.

Common situations: Using a custom functional interface instead of java.util.function.Function; Kotlin lambdas typed as Function3+; raw lambdas assigned to Object variables; generics erased so ResolvableType sees NONE.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/08eac5519d522975. Report an issue: GitHub.

Appendix: source

Thrown at spring-ai-model/src/main/java/org/springframework/ai/tool/resolution/TypeResolverHelper.java:267

			functionArgumentResolvableType = functionType.as(Supplier.class);
		}
		else if (Consumer.class.isAssignableFrom(resolvableClass)) {
			functionArgumentResolvableType = functionType.as(Consumer.class);
		}
		else if (KotlinDetector.isKotlinPresent()) {
			if (KotlinDelegate.isKotlinFunction(resolvableClass)) {
				functionArgumentResolvableType = KotlinDelegate.adaptToKotlinFunctionType(functionType);
			}
			else if (KotlinDelegate.isKotlinBiFunction(resolvableClass)) {
				functionArgumentResolvableType = KotlinDelegate.adaptToKotlinBiFunctionType(functionType);
			}
			else if (KotlinDelegate.isKotlinSupplier(resolvableClass)) {
				functionArgumentResolvableType = KotlinDelegate.adaptToKotlinSupplierType(functionType);
			}
		}

		if (functionArgumentResolvableType == ResolvableType.NONE) {
			throw new IllegalArgumentException(
					"Type must be a Function, BiFunction, Function1 or Function2. Found: " + functionType);
		}

		return functionArgumentResolvableType.getGeneric(argumentIndex);
	}

	private static final class KotlinDelegate {

		public static boolean isKotlinSupplier(Class<?> clazz) {
			return Function0.class.isAssignableFrom(clazz);
		}

		public static ResolvableType adaptToKotlinSupplierType(ResolvableType resolvableType) {
			return resolvableType.as(Function0.class);
		}

		public static boolean isKotlinFunction(Class<?> clazz) {
			return Function1.class.isAssignableFrom(clazz);

View on GitHub (pinned to 98a7beda4f)