spring-projects/spring-ai · error · IllegalArgumentException

Method must return either GetPromptResult, List<PromptMessag

Error message

Method must return either GetPromptResult, List<PromptMessage>, List<String>, PromptMessage, or String: ${method} in ${declaringClass} returns ${returnType}

What it means

Identical to the stateful sync prompt check (error 190) but in SyncStatelessMcpPromptMethodCallback: a @McpPrompt method in a stateless Streamable-Http server must return GetPromptResult, List, PromptMessage, or String. validateReturnType throws IllegalArgumentException for any other return type, failing at startup.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/SyncStatelessMcpPromptMethodCallback.java:144

				.build();
		}
	}

	@Override
	protected boolean isSupportedExchangeOrContextType(Class<?> paramType) {
		return McpTransportContext.class.isAssignableFrom(paramType);
	}

	@Override
	protected void validateReturnType(Method method) {
		Class<?> returnType = method.getReturnType();

		boolean validReturnType = GetPromptResult.class.isAssignableFrom(returnType)
				|| List.class.isAssignableFrom(returnType) || PromptMessage.class.isAssignableFrom(returnType)
				|| String.class.isAssignableFrom(returnType);

		if (!validReturnType) {
			throw new IllegalArgumentException("Method must return either GetPromptResult, List<PromptMessage>, "
					+ "List<String>, PromptMessage, or String: " + method.getName() + " in "
					+ method.getDeclaringClass().getName() + " returns " + returnType.getName());
		}
	}

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

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

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Change the return type to GetPromptResult, List<PromptMessage>, List<String>, PromptMessage, or String.
  2. Convert custom DTOs into PromptMessage instances with appropriate Content.
  3. Return a simple String for plain-text prompts.

Example fix

// before
@McpPrompt(description = "summary")
public SummaryReport summarize(String topic) {
    return new SummaryReport(topic);
}

// after
@McpPrompt(description = "summary")
public PromptMessage summarize(String topic) {
    return new PromptMessage(Role.ASSISTANT, new TextContent("Summary of " + topic));
}
Defensive patterns

Strategy: validation

Validate before calling

static boolean hasValidStatelessPromptReturnType(Method m) {
    Class<?> r = m.getReturnType();
    return GetPromptResult.class.isAssignableFrom(r) || List.class.isAssignableFrom(r)
        || PromptMessage.class.isAssignableFrom(r) || String.class.isAssignableFrom(r);
}

Try / catch

try {
    statelessServer.addPrompt(spec);
} catch (IllegalArgumentException e) {
    throw new IllegalStateException("@McpPrompt return type not supported in stateless server", e);
}

Prevention

When it happens

Trigger: Annotating a prompt method in a stateless server whose return type is a POJO, Optional, primitive, Map, or other non-whitelisted type; the same whitelist check as the stateful variant is applied at registration.

Common situations: Reusing tool methods as prompts (tools allow broader returns); returning builder-style custom result objects; migrating methods between sync/async callbacks where return-type rules differ.

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/6efde408e3f2baef. Report an issue: GitHub.