{"record":{"id":"7e2c1a7e5bbf6ab1","repo":"spring-projects/spring-ai","slug":"method-must-return-either-getpromptresult-list-pr","errorCode":null,"errorMessage":"Method must return either GetPromptResult, List<PromptMessage>, List<String>, PromptMessage, String, or Mono<T>: {method.getName()} in {method.getDeclaringClass().getName()} returns {returnType.getName()}","messagePattern":"Method must return either GetPromptResult, List<PromptMessage>, List<String>, PromptMessage, String, or Mono<T>: (.+?) in (.+?) returns (.+?)","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AsyncStatelessMcpPromptMethodCallback.java","lineNumber":156,"sourceCode":"\t\t\t}\n\t\t});\n\t}\n\n\t@Override\n\tprotected boolean isSupportedExchangeOrContextType(Class<?> paramType) {\n\t\treturn McpTransportContext.class.isAssignableFrom(paramType);\n\t}\n\n\t@Override\n\tprotected void validateReturnType(Method method) {\n\t\tClass<?> returnType = method.getReturnType();\n\n\t\tboolean validReturnType = GetPromptResult.class.isAssignableFrom(returnType)\n\t\t\t\t|| List.class.isAssignableFrom(returnType) || PromptMessage.class.isAssignableFrom(returnType)\n\t\t\t\t|| String.class.isAssignableFrom(returnType) || Mono.class.isAssignableFrom(returnType);\n\n\t\tif (!validReturnType) {\n\t\t\tthrow new IllegalArgumentException(\"Method must return either GetPromptResult, List<PromptMessage>, \"\n\t\t\t\t\t+ \"List<String>, PromptMessage, String, or Mono<T>: \" + method.getName() + \" in \"\n\t\t\t\t\t+ method.getDeclaringClass().getName() + \" returns \" + returnType.getName());\n\t\t}\n\t}\n\n\t/**\n\t * Create a new builder.\n\t * @return A new builder instance\n\t */\n\tpublic static Builder builder() {\n\t\treturn new Builder();\n\t}\n\n\t/**\n\t * Builder for creating AsyncStatelessMcpPromptMethodCallback instances.\n\t * <p>\n\t * This builder provides a fluent API for constructing\n\t * AsyncStatelessMcpPromptMethodCallback instances with the required parameters.","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AsyncStatelessMcpPromptMethodCallback.java#L138-L174","documentation":"AsyncStatelessMcpPromptMethodCallback validates that the prompt method returns one of GetPromptResult, List (e.g. List<PromptMessage> or List<String>), PromptMessage, String, or a Mono of any of these. Any other return type is rejected with IllegalArgumentException because the callback cannot convert it into a prompt response.","triggerScenarios":"Registering an @McpPrompt method whose return type is a POJO, Map, CompletableFuture, or other non-supported type while using the async stateless callback.","commonSituations":"Returning custom domain objects from prompt methods; forgetting to map a domain object to GetPromptResult/PromptMessage; using CompletableFuture instead of Mono.","solutions":["Change the return type to one of GetPromptResult, List<PromptMessage>, List<String>, PromptMessage, String, or Mono<T> of those","Map your custom result into a GetPromptResult or PromptMessage before returning","Convert CompletableFuture to Mono using Mono.fromFuture(...)"],"exampleFix":"// before\n@McpPrompt(description = \"p\")\npublic MyResult p(Request req) {...}\n// after\n@McpPrompt(description = \"p\")\npublic Mono<GetPromptResult> p(Request req) { return Mono.just(new GetPromptResult(description)); }","handlingStrategy":"validation","validationCode":"Set<Class<?>> ok = Set.of(GetPromptResult.class, List.class, PromptMessage.class, String.class, Mono.class); if (ok.stream().noneMatch(c -> c.isAssignableFrom(method.getReturnType()))) throw new IllegalStateException(\"bad return type\");","typeGuard":null,"tryCatchPattern":"try { server.addPrompt(cb); } catch (IllegalArgumentException e) { /* fix return type */ }","preventionTips":["Return GetPromptResult/PromptMessage/String or their Mono wrappers only","Map domain objects to GetPromptResult before returning","Use Mono.fromFuture instead of CompletableFuture returns"],"tags":["mcp","return-type","prompt-method"],"backgroundTag":"type-mismatch","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}