spring-projects/spring-ai · error · IllegalArgumentException
Method must return either GetPromptResult, List<PromptMessag
Error message
Method must return either GetPromptResult, List<PromptMessage>, List<String>, PromptMessage, or String: ${method} in ${declaringClass} returns ${returnType} What it means
A @McpPrompt-annotated method registered with the sync MCP prompt callback returns a type the framework cannot convert into a prompt result. The library validates the method's return type against a whitelist (GetPromptResult, List, PromptMessage, String) and throws IllegalArgumentException when none match. This fails fast at registration/startup rather than at request time.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/SyncMcpPromptMethodCallback.java:151
}
}
@Override
protected boolean isSupportedExchangeOrContextType(Class<?> paramType) {
return (McpSyncServerExchange.class.isAssignableFrom(paramType)
|| McpTransportContext.class.isAssignableFrom(paramType));
}
@Override
protected void validateReturnType(Method method) {
Class<?> returnType = method.getReturnType();
boolean validReturnType = GetPromptResult.class.isAssignableFrom(returnType)
|| List.class.isAssignableFrom(returnType) || PromptMessage.class.isAssignableFrom(returnType)
|| String.class.isAssignableFrom(returnType);
if (!validReturnType) {
throw new IllegalArgumentException("Method must return either GetPromptResult, List<PromptMessage>, "
+ "List<String>, PromptMessage, or String: " + method.getName() + " in "
+ method.getDeclaringClass().getName() + " returns " + returnType.getName());
}
}
/**
* Create a new builder.
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}
/**
* Builder for creating SyncMcpPromptMethodCallback instances.
* <p>
* This builder provides a fluent API for constructing SyncMcpPromptMethodCallback
* instances with the required parameters.View on GitHub (pinned to 98a7beda4f)
Solutions
- Change the method's return type to GetPromptResult, List<PromptMessage>, List<String>, PromptMessage, or String.
- Wrap custom message data in PromptMessage with role and content (TextContent or EmbeddedResource).
- If the result is async/reactive, move to the async callback variant or block/convert to a sync type before returning.
- For lists of arbitrary strings, return List<String> which the framework converts into message content.
Example fix
// before
@McpPrompt(description = "greet")
public GreetingDto greet(String name) {
return new GreetingDto("Hello " + name);
}
// after
@McpPrompt(description = "greet")
public String greet(String name) {
return "Hello " + name;
} Defensive patterns
Strategy: validation
Validate before calling
static boolean hasValidPromptReturnType(Method m) {
Class<?> r = m.getReturnType();
return GetPromptResult.class.isAssignableFrom(r) || List.class.isAssignableFrom(r)
|| PromptMessage.class.isAssignableFrom(r) || String.class.isAssignableFrom(r);
}
// assert hasValidPromptReturnType(promptMethod) before registration; Try / catch
try {
server.addPrompt(promptSpec);
} catch (IllegalArgumentException e) {
log.error("Prompt method signature invalid: {}", e.getMessage());
throw new IllegalStateException("Fix @McpPrompt return type", e);
} Prevention
- Only return whitelisted types (GetPromptResult, List<PromptMessage>, List<String>, PromptMessage, String) from @McpPrompt methods.
- Write an arch-unit or unit test that scans all @McpPrompt methods and asserts return-type validity at CI time.
- Do not reuse tool method signatures as prompt methods without reviewing the return type.
When it happens
Trigger: Registering a prompt method (e.g. via McpServerFeatures or the annotations auto-config) whose return type is a POJO, CompletableFuture, Optional, custom wrapper, or primitive not on the allowed list; validateReturnType checks GetPromptResult/List/PromptMessage/String assignability and throws otherwise.
Common situations: Returning a custom DTO class directly; forgetting to wrap messages in PromptMessage; returning reactor Mono/Flux in a sync callback; copy-pasting a method that worked as a tool (where return types are broader) into a @McpPrompt method.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Method must return either GetPromptResult, List<PromptMessag
- Either prompt or uri must be provided in McpComplete annotat
- Only one of prompt or uri can be provided in McpComplete ann
- Method must have exactly 1 parameter (List<McpSchema.Resourc
- Parameter must be of type List<McpSchema.Resource>:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/dbbfebc5ffd34538.
Report an issue: GitHub.