{"record":{"id":"f64c57c637332d9f","repo":"spring-projects/spring-ai","slug":"third-parameter-must-be-of-type-string","errorCode":null,"errorMessage":"Third parameter must be of type String: ","messagePattern":"Third parameter must be of type String: ","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":123,"sourceCode":"\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()\n\t\t\t\t\t\t+ \" in \" + method.getDeclaringClass().getName() + \" has parameter of type \"\n\t\t\t\t\t\t+ parameters[2].getType().getName());\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Builds the arguments array for invoking the method.\n\t * <p>\n\t * This method constructs an array of arguments based on the method's parameter types\n\t * and the available values (exchange, notification).\n\t * @param method The method to build arguments for\n\t * @param exchange The server exchange\n\t * @param notification The logging message notification\n\t * @return An array of arguments for the method invocation\n\t */\n\tprotected Object[] buildArgs(Method method, Object exchange, LoggingMessageNotification notification) {\n\t\tParameter[] parameters = method.getParameters();","sourceCodeStart":105,"sourceCodeEnd":141,"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#L105-L141","documentation":"Thrown during parameter validation of an @McpLogging method callback when the callback declares multiple parameters and its third parameter's type is not assignable to String. The multi-parameter form must be (LoggingLevel, String, String), where the third parameter carries the log message payload; a non-String third parameter means the callback can never be invoked with a decoded notification. This fails fast at registration time via validateMethod rather than deferring the mismatch to message delivery.","triggerScenarios":"Registering a @McpLogging method like (LoggingLevel, String, Object) or (LoggingLevel, String, Map).","commonSituations":"Developer expects structured payload data as the third argument; message passed as a custom type; refactoring changed the parameter type after registration.","solutions":["Change the third parameter to String (the logger name)"],"exampleFix":"// before\n@McpLogging(clients = \"client1\")\npublic void onLog(LoggingLevel level, String logger, Map<String, Object> data) { ... }\n// after\n@McpLogging(clients = \"client1\")\npublic void onLog(LoggingLevel level, String logger, String message) { ... }","handlingStrategy":"validation","validationCode":"if (m.getParameterCount() == 3\n        && !String.class.isAssignableFrom(m.getParameterTypes()[2])) {\n    throw new IllegalStateException(\"third param must be String\");\n}","typeGuard":"static boolean thirdParamIsString(Method m) {\n    return m.getParameterCount() == 3\n        && String.class.isAssignableFrom(m.getParameterTypes()[2]);\n}","tryCatchPattern":null,"preventionTips":["Third parameter is the message as a String","Use the single LoggingMessageNotification signature for structured payloads"],"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"}