{"record":{"id":"ab6bb4f6c184dcd8","repo":"spring-projects/spring-ai","slug":"single-parameter-must-be-of-type-loggingmessagenot","errorCode":null,"errorMessage":"Single parameter must be of type LoggingMessageNotification: ","messagePattern":"Single parameter must be of type LoggingMessageNotification: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/logging/AbstractMcpLoggingMethodCallback.java","lineNumber":105,"sourceCode":"\t * @param method The method to validate\n\t * @throws IllegalArgumentException if the parameters are not compatible\n\t */\n\tprotected void validateParameters(Method method) {\n\t\tParameter[] parameters = method.getParameters();\n\n\t\t// Check parameter count - must have either 1 or 3 parameters\n\t\tif (parameters.length != 1 && parameters.length != 3) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Method must have either 1 parameter (LoggingMessageNotification) or 3 parameters (LoggingLevel, String, String): \"\n\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName() + \" has \"\n\t\t\t\t\t\t\t+ parameters.length + \" parameters\");\n\t\t}\n\n\t\t// Check parameter types\n\t\tif (parameters.length == 1) {\n\t\t\t// Single parameter must be LoggingMessageNotification\n\t\t\tif (!LoggingMessageNotification.class.isAssignableFrom(parameters[0].getType())) {\n\t\t\t\tthrow new IllegalArgumentException(\"Single parameter must be of type LoggingMessageNotification: \"\n\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName() + \" has parameter of type \"\n\t\t\t\t\t\t+ parameters[0].getType().getName());\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Three parameters must be LoggingLevel, String, String\n\t\t\tif (!LoggingLevel.class.isAssignableFrom(parameters[0].getType())) {\n\t\t\t\tthrow new IllegalArgumentException(\"First parameter must be of type LoggingLevel: \" + method.getName()\n\t\t\t\t\t\t+ \" in \" + method.getDeclaringClass().getName() + \" has parameter of type \"\n\t\t\t\t\t\t+ parameters[0].getType().getName());\n\t\t\t}\n\t\t\tif (!String.class.isAssignableFrom(parameters[1].getType())) {\n\t\t\t\tthrow new IllegalArgumentException(\"Second parameter must be of type String: \" + method.getName()\n\t\t\t\t\t\t+ \" in \" + method.getDeclaringClass().getName() + \" has parameter of type \"\n\t\t\t\t\t\t+ parameters[1].getType().getName());\n\t\t\t}\n\t\t\tif (!String.class.isAssignableFrom(parameters[2].getType())) {\n\t\t\t\tthrow new IllegalArgumentException(\"Third parameter must be of type String: \" + method.getName()","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/logging/AbstractMcpLoggingMethodCallback.java#L87-L123","documentation":"For 1-parameter logging handlers, validateParameters() checks that the sole parameter type is assignable to LoggingMessageNotification. A handler taking some other single object type cannot receive the MCP logging notification and is rejected with IllegalArgumentException.","triggerScenarios":"Registering a @McpLogging method with one parameter of type String, Map, or a custom DTO instead of LoggingMessageNotification.","commonSituations":"Developer assumes the notification payload is delivered directly as a String/Map; using a shared DTO that wraps the notification; schema change after upgrading the MCP SDK.","solutions":["Change the parameter type to LoggingMessageNotification","Extract the message/level inside the handler from the notification object","Or switch to the 3-parameter (LoggingLevel, String, String) form"],"exampleFix":"// before\n@McpLogging(clients = \"client1\")\npublic void onLog(String message) { ... }\n// after\n@McpLogging(clients = \"client1\")\npublic void onLog(LoggingMessageNotification notification) {\n    String message = notification.data();\n}","handlingStrategy":"validation","validationCode":"if (m.getParameterCount() == 1\n        && !LoggingMessageNotification.class.isAssignableFrom(m.getParameterTypes()[0])) {\n    throw new IllegalStateException(\"single param must be LoggingMessageNotification\");\n}","typeGuard":"static boolean hasNotificationParam(Method m) {\n    return m.getParameterCount() == 1\n        && LoggingMessageNotification.class.isAssignableFrom(m.getParameterTypes()[0]);\n}","tryCatchPattern":null,"preventionTips":["Accept LoggingMessageNotification and extract data/level inside the handler","Do not assume the framework unwraps payloads into Strings or Maps"],"tags":["mcp","logging","parameter-type","java"],"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"}