{"record":{"id":"4c3b2240abe2988a","repo":"spring-projects/spring-ai","slug":"method-must-return-mono-elicitresult-or-mono-stru","errorCode":null,"errorMessage":"Method must return Mono<ElicitResult> or Mono<StructuredElicitResult>: ","messagePattern":"Method must return Mono<ElicitResult> or Mono<StructuredElicitResult>: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/elicitation/AsyncMcpElicitationMethodCallback.java","lineNumber":119,"sourceCode":"\t\t\t\t\t\"Method must return Mono<ElicitResult> or Mono<StructuredElicitResult>: \" + this.method.getName()));\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\treturn Mono.error(new McpElicitationMethodException(\n\t\t\t\t\t\"Error invoking elicitation method: \" + this.method.getName(), e));\n\t\t}\n\t}\n\n\t/**\n\t * Validates that the method return type is compatible with the elicitation callback.\n\t * @param method The method to validate\n\t * @throws IllegalArgumentException if the return type is not compatible\n\t */\n\t@Override\n\tprotected void validateReturnType(Method method) {\n\t\tClass<?> returnType = method.getReturnType();\n\n\t\tif (!Mono.class.isAssignableFrom(returnType)) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Method must return Mono<ElicitResult> or Mono<StructuredElicitResult>: \" + method.getName()\n\t\t\t\t\t\t\t+ \" in \" + method.getDeclaringClass().getName() + \" returns \" + returnType.getName());\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a parameter type is compatible with the exchange type.\n\t * @param paramType The parameter type to check\n\t * @return true if the parameter type is compatible with the exchange type, false\n\t * otherwise\n\t */\n\t@Override\n\tprotected boolean isExchangeType(Class<?> paramType) {\n\t\t// No exchange type for elicitation methods\n\t\treturn false;\n\t}\n\n\t/**","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/elicitation/AsyncMcpElicitationMethodCallback.java#L101-L137","documentation":"Thrown by AsyncMcpElicitationMethodCallback.validateReturnType when an async @McpElicitation-annotated method's return type is not a Mono. Async elicitation handlers must return Mono<ElicitResult> (or Mono<StructuredElicitResult>) so the framework can subscribe reactively.","triggerScenarios":"Registering a handler on the async callback path declared as public ElicitResult handle(ElicitRequest req) (sync return) or returning Flux/CompletableFuture instead of Mono.","commonSituations":"Using @McpElicitation in a reactive (WebFlux / async MCP client) setup but writing the handler in blocking style, or migrating a sync handler to async without changing the return type.","solutions":["Change the return type to Mono<ElicitResult>","Wrap a blocking computation with Mono.fromCallable(() -> computeResult(req))","If the method is inherently synchronous, register it via the sync specification/callback instead of the async one","For structured payloads return Mono<StructuredElicitResult> instead"],"exampleFix":"// before\n@McpElicitation\npublic ElicitResult handle(ElicitRequest request) { return compute(request); }\n\n// after\n@McpElicitation\npublic Mono<ElicitResult> handle(ElicitRequest request) {\n    return Mono.fromCallable(() -> compute(request));\n}\n","handlingStrategy":"validation","validationCode":"if (!Mono.class.isAssignableFrom(handlerMethod.getReturnType())) {\n    throw new IllegalArgumentException(\"Async elicitation handler must return Mono<ElicitResult>: \" + handlerMethod);\n}","typeGuard":"boolean isAsyncElicitationHandler(Method m) {\n    return Mono.class.isAssignableFrom(m.getReturnType());\n}","tryCatchPattern":null,"preventionTips":["Return Mono<ElicitResult> (or Mono<StructuredElicitResult>) from async handlers","Use Mono.fromCallable to adapt blocking code","Use sync registration for plain blocking handlers instead of forcing Mono"],"tags":["java","mcp","elicitation","reactor","return-type"],"backgroundTag":"type-mismatch","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}