{"record":{"id":"0c8bb8d271f67670","repo":"spring-projects/spring-ai","slug":"method-must-have-either-1-parameter-loggingmessag","errorCode":null,"errorMessage":"Method must have either 1 parameter (LoggingMessageNotification) or 3 parameters (LoggingLevel, String, String): ","messagePattern":"Method must have either 1 parameter \\(LoggingMessageNotification\\) or 3 parameters \\(LoggingLevel, String, 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":95,"sourceCode":"\t * callback. This method should be implemented by subclasses to handle specific return\n\t * type validation.\n\t * @param method The method to validate\n\t * @throws IllegalArgumentException if the return type is not compatible\n\t */\n\tprotected abstract void validateReturnType(Method method);\n\n\t/**\n\t * Validates method parameters. This method provides common validation logic and\n\t * delegates exchange type checking to subclasses.\n\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()","sourceCodeStart":77,"sourceCodeEnd":113,"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#L77-L113","documentation":"validateParameters() in AbstractMcpLoggingMethodCallback requires an @McpLogging handler to accept exactly 1 parameter (a LoggingMessageNotification) or exactly 3 parameters (LoggingLevel, String, String). Any other arity is rejected with IllegalArgumentException at registration time.","triggerScenarios":"Registering a logging handler with 0, 2, or 4+ parameters; using varargs; passing a method intended for a different MCP annotation type.","commonSituations":"Developer writes a handler with extra context parameters (e.g. McpSyncServerExchange plus payload); copy-paste from a tool callback that has different signatures; overload resolution picks the wrong method.","solutions":["Change the handler to a single LoggingMessageNotification parameter","Or use the 3-parameter form (LoggingLevel level, String logger, String message)","Remove extra parameters and obtain context via fields or the exchange passed at construction"],"exampleFix":"// before\n@McpLogging(clients = \"client1\")\npublic void onLog(McpSyncServerExchange exchange, LoggingMessageNotification n) { ... }\n// after\n@McpLogging(clients = \"client1\")\npublic void onLog(LoggingMessageNotification n) { ... }","handlingStrategy":"validation","validationCode":"int n = loggingMethod.getParameterCount();\nif (n != 1 && n != 3) {\n    throw new IllegalStateException(loggingMethod.getName() + \" must take 1 or 3 parameters, has \" + n);\n}","typeGuard":"static boolean isValidLoggingArity(Method m) {\n    return m.getParameterCount() == 1 || m.getParameterCount() == 3;\n}","tryCatchPattern":null,"preventionTips":["Use only the two supported signatures: (LoggingMessageNotification) or (LoggingLevel, String, String)","Do not add context parameters like McpSyncServerExchange to logging handlers","Add an architecture test scanning @McpLogging methods for arity"],"tags":["mcp","logging","method-signature","java"],"backgroundTag":"invalid-argument-format","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"}