{"record":{"id":"4d0a2a7eec2da4cb","repo":"spring-projects/spring-ai","slug":"currently-only-methods-with-a-single-createmessage-4d0a2a","errorCode":null,"errorMessage":"Currently only methods with a single CreateMessageRequest parameter are supported","messagePattern":"Currently only methods with a single CreateMessageRequest parameter are supported","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/sampling/AbstractMcpSamplingMethodCallback.java","lineNumber":140,"sourceCode":"\t * and the available values (exchange, request).\n\t * @param method The method to build arguments for\n\t * @param exchange The server exchange\n\t * @param request The sampling request\n\t * @return An array of arguments for the method invocation\n\t */\n\tprotected Object[] buildArgs(Method method, Object exchange, CreateMessageRequest request) {\n\t\tParameter[] parameters = method.getParameters();\n\t\tObject[] args = new Object[parameters.length];\n\n\t\tif (parameters.length == 1) {\n\t\t\t// Single parameter (CreateMessageRequest)\n\t\t\targs[0] = request;\n\t\t}\n\t\telse {\n\t\t\t// TODO: Support for multiple parameters corresponding to CreateMessageRequest\n\t\t\t// fields\n\t\t\t// For now, we only support the single parameter version\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Currently only methods with a single CreateMessageRequest parameter are supported\");\n\t\t}\n\n\t\treturn args;\n\t}\n\n\t/**\n\t * Checks if a parameter type is compatible with the exchange type. This method should\n\t * be implemented by subclasses to handle specific exchange type checking.\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\tprotected abstract boolean isExchangeType(Class<?> paramType);\n\n\t/**\n\t * Exception thrown when there is an error invoking a sampling method.\n\t */","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/sampling/AbstractMcpSamplingMethodCallback.java#L122-L158","documentation":"buildArgs() assembles the runtime arguments passed to the annotated sampling method and only implements the single CreateMessageRequest-parameter case. If the method's parameter count is not 1 at invocation time it throws IllegalArgumentException. This is a defensive runtime check mirroring the earlier validateParameters() registration-time validation.","triggerScenarios":"Invoking a sampling callback whose method declares 0 or 2+ parameters — typically possible only when a subclass overrides validation or the method was mutated/registered without running validateMethod.","commonSituations":"Custom subclasses of AbstractMcpSamplingMethodCallback that skip or weaken validateParameters() then fail at call time; framework-internal invariant breach when reflection metadata desyncs from the built args array.","solutions":["Ensure the sampling method has exactly one CreateMessageRequest parameter","If writing a custom callback subclass, call validateParameters() (or replicate the count==1 contract) before invocation","Treat this as a bug report trigger: file an issue with the method signature if validation passed but buildArgs still throws"],"exampleFix":"// before\nMethod m = beanClass.getMethod(\"handle\", CreateMessageRequest.class, String.class);\nnew AbstractMcpSamplingMethodCallback(builder.method(m)); // skips validation\n// after\nnew AbstractMcpSamplingMethodCallback(builder.method(beanClass.getMethod(\"handle\", CreateMessageRequest.class))); // validateMethod enforces single param","handlingStrategy":"try-catch","validationCode":"if (method.getParameterCount() != 1\n        || !CreateMessageRequest.class.isAssignableFrom(method.getParameterTypes()[0])) {\n    throw new IllegalStateException(\"Callback method must take exactly one CreateMessageRequest\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Object result = callback.call(request);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"single CreateMessageRequest parameter are supported\")) {\n        throw new IllegalStateException(\"Misconfigured sampling callback: \" + callback, e);\n    } else { throw e; }\n}","preventionTips":["Always construct callbacks through the standard builder so validateParameters runs","If subclassing, invoke validateMethod() in your constructor","Report to the library if this throws despite a valid single-parameter method — it indicates a metadata desync bug"],"tags":["java","mcp","sampling","internal","reflection"],"backgroundTag":"internal-invariant-violation","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}