spring-projects/spring-ai · error · McpCompleteMethodException

Error invoking complete method:

Error message

Error invoking complete method: 

What it means

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.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/SyncStatelessMcpCompleteMethodCallback.java:80

	@Override
	public CompleteResult apply(McpTransportContext context, CompleteRequest request) {
		if (request == null) {
			throw new IllegalArgumentException("Request must not be null");
		}

		try {
			// Build arguments for the method call
			Object[] args = this.buildArgs(this.method, context, request);

			// Invoke the method
			this.method.setAccessible(true);
			Object result = this.method.invoke(this.bean, args);

			// Convert the result to a CompleteResult
			return convertToCompleteResult(result);
		}
		catch (Exception e) {
			throw new McpCompleteMethodException("Error invoking complete method: " + this.method.getName(), e);
		}
	}

	/**
	 * Converts the method result to a CompleteResult.
	 * @param result The method result
	 * @return The CompleteResult
	 */
	private CompleteResult convertToCompleteResult(Object result) {
		if (result == null) {
			return new CompleteResult(new CompleteCompletion(List.of(), 0, false));
		}

		if (result instanceof CompleteResult) {
			return (CompleteResult) result;
		}

		if (result instanceof CompleteCompletion) {

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Read the cause of the McpCompleteMethodException (e.getCause()) to find the real failure
  2. Fix the underlying exception in the @McpComplete handler method
  3. Make the handler method public and its class accessible if IllegalAccessException is the cause
  4. Wrap risky handler logic in try-catch inside the method and return an empty CompleteCompletion on failure

Example fix

// before
@McpComplete(promptName = "p")
public List<String> complete(String v) { return repo.suggest(v); } // throws on DB outage
// after
@McpComplete(promptName = "p")
public List<String> complete(String v) {
    try { return repo.suggest(v); } catch (Exception e) { return List.of(); }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify handler is public and callable before registration
Method m = bean.getClass().getMethod(handlerName, ElicitRequest.class); // or relevant signature
if (!Modifier.isPublic(m.getModifiers())) throw new IllegalStateException("handler must be public");

Try / catch

try { return callback.apply(context, request); }
catch (McpCompleteMethodException e) {
    log.error("complete handler '{}' failed: {}", e.getMessage(), e.getCause(), e.getCause());
    return new CompleteResult(new CompleteCompletion(List.of(), 0, false));
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/1bfc69db05add7ea. Report an issue: GitHub.