{"record":{"id":"1bfc69db05add7ea","repo":"spring-projects/spring-ai","slug":"error-invoking-complete-method-1bfc69","errorCode":null,"errorMessage":"Error invoking complete method: ","messagePattern":"Error invoking complete method: ","errorType":"exception","errorClass":"McpCompleteMethodException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/SyncStatelessMcpCompleteMethodCallback.java","lineNumber":80,"sourceCode":"\t@Override\n\tpublic CompleteResult apply(McpTransportContext context, CompleteRequest request) {\n\t\tif (request == null) {\n\t\t\tthrow new IllegalArgumentException(\"Request must not be null\");\n\t\t}\n\n\t\ttry {\n\t\t\t// Build arguments for the method call\n\t\t\tObject[] args = this.buildArgs(this.method, context, request);\n\n\t\t\t// Invoke the method\n\t\t\tthis.method.setAccessible(true);\n\t\t\tObject result = this.method.invoke(this.bean, args);\n\n\t\t\t// Convert the result to a CompleteResult\n\t\t\treturn convertToCompleteResult(result);\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new McpCompleteMethodException(\"Error invoking complete method: \" + this.method.getName(), e);\n\t\t}\n\t}\n\n\t/**\n\t * Converts the method result to a CompleteResult.\n\t * @param result The method result\n\t * @return The CompleteResult\n\t */\n\tprivate CompleteResult convertToCompleteResult(Object result) {\n\t\tif (result == null) {\n\t\t\treturn new CompleteResult(new CompleteCompletion(List.of(), 0, false));\n\t\t}\n\n\t\tif (result instanceof CompleteResult) {\n\t\t\treturn (CompleteResult) result;\n\t\t}\n\n\t\tif (result instanceof CompleteCompletion) {","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/SyncStatelessMcpCompleteMethodCallback.java#L62-L98","documentation":"SyncStatelessMcpCompleteMethodCallback.apply wraps any Exception thrown while reflectively invoking the user's @McpComplete method into a McpCompleteMethodException with message \"Error invoking complete method: <methodName>\". It indicates the user handler itself failed (or result conversion failed), not the MCP transport.","triggerScenarios":"The annotated handler method throws (NPE, IO error, DB failure), method.invoke fails due to IllegalAccessException, or convertToCompleteResult throws (e.g. non-String list items or unsupported return type) while processing a completion request.","commonSituations":"Handler code dereferences a null request field, a downstream service is down, or the method's declaring class is not accessible (private/nested class without setAccessible); always inspect the wrapped cause.","solutions":["Read the cause of the McpCompleteMethodException (e.getCause()) to find the real failure","Fix the underlying exception in the @McpComplete handler method","Make the handler method public and its class accessible if IllegalAccessException is the cause","Wrap risky handler logic in try-catch inside the method and return an empty CompleteCompletion on failure"],"exampleFix":"// before\n@McpComplete(promptName = \"p\")\npublic List<String> complete(String v) { return repo.suggest(v); } // throws on DB outage\n// after\n@McpComplete(promptName = \"p\")\npublic List<String> complete(String v) {\n    try { return repo.suggest(v); } catch (Exception e) { return List.of(); }\n}","handlingStrategy":"try-catch","validationCode":"// verify handler is public and callable before registration\nMethod m = bean.getClass().getMethod(handlerName, ElicitRequest.class); // or relevant signature\nif (!Modifier.isPublic(m.getModifiers())) throw new IllegalStateException(\"handler must be public\");","typeGuard":null,"tryCatchPattern":"try { return callback.apply(context, request); }\ncatch (McpCompleteMethodException e) {\n    log.error(\"complete handler '{}' failed: {}\", e.getMessage(), e.getCause(), e.getCause());\n    return new CompleteResult(new CompleteCompletion(List.of(), 0, false));\n}","preventionTips":["Always log e.getCause() — the top message only names the method","Keep handler bodies defensive (null-check fields, guard downstream calls)","Make handler methods public and their beans accessible to reflection","Handle expected failures inside the handler and return empty completions instead of throwing"],"tags":["java","mcp","reflection","wrapped-exception"],"backgroundTag":"invalid-argument-value","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"}