spring-projects/spring-ai · error · McpProgressMethodException

Error invoking progress method: {this.method.getName()}

Error message

Error invoking progress method: {this.method.getName()}

What it means

When the annotated progress method itself throws while being reflectively invoked by AsyncMcpProgressMethodCallback.apply, the exception is wrapped in an McpProgressMethodException with this message naming the failing method. The original cause is attached, so it indicates a runtime failure inside user handler code, not a signature problem.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/progress/AsyncMcpProgressMethodCallback.java:109

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

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

				// Handle return type
				if (result instanceof Mono) {
					return (Mono<?>) result;
				}
				else {
					// void return type
					return Mono.empty();
				}
			}
			catch (Exception e) {
				throw new McpProgressMethodException("Error invoking progress method: " + this.method.getName(), e);
			}
		}).flatMap(mono -> mono.then());
	}

	/**
	 * Create a new builder.
	 * @return A new builder instance
	 */
	public static Builder builder() {
		return new Builder();
	}

	/**
	 * Builder for creating AsyncMcpProgressMethodCallback instances.
	 * <p>
	 * This builder provides a fluent API for constructing AsyncMcpProgressMethodCallback
	 * instances with the required parameters.
	 */

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Inspect the cause chain of the McpProgressMethodException and fix the underlying exception in the handler method.
  2. Add defensive null/argument checks inside the progress handler before using notification values.
  3. Wrap risky handler logic in try-catch or onErrorResume to degrade gracefully instead of failing the notification.

Example fix

// before
public void onProgress(Double p, String token, String msg) {
    tracker.update(token, p); // NPE if tracker not initialized
}
// after
public void onProgress(Double p, String token, String msg) {
    if (tracker != null) tracker.update(token, p);
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
    callback.accept(notification);
} catch (McpProgressMethodException e) {
    log.error("Progress handler {} failed: {}", e.getMessage(), e.getCause(), e);
    // do not rethrow if progress failure must not abort the main operation
}

Prevention

When it happens

Trigger: The progress handler method (void or Mono-producing path) throws an exception during synchronous part of its execution when a ProgressNotification is applied via the callback.

Common situations: NPE inside the handler from unvalidated notification fields; illegalStateException from accessing closed resources; any user-code bug surfaced during progress delivery from a client (e.g. during long-running tool execution).

Related errors


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