spring-projects/spring-ai · error · java.lang.IllegalArgumentException
Unsupported Async exchange type: {asyncServerExchange.getCla
Error message
Unsupported Async exchange type: {asyncServerExchange.getClass().getName()} for Sync method: {method.getName()} in {method.getDeclaringClass().getName()} What it means
When a sync prompt method declares an McpTransportContext parameter, assignExchangeType converts the incoming exchange into a context. An McpAsyncServerExchange arriving at a Sync method cannot be converted, so the callback throws IllegalArgumentException naming the unsupported async exchange type.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/SyncMcpPromptMethodCallback.java:72
if (McpAsyncServerExchange.class.isAssignableFrom(paramType)) {
throw new IllegalArgumentException("Sync prompt method must not declare parameter of type: "
+ paramType.getName() + ". Use McpSyncServerExchange instead." + " Method: " + this.method.getName()
+ " in " + this.method.getDeclaringClass().getName());
}
}
@Override
protected Object assignExchangeType(Class<?> paramType, Object exchange) {
if (McpTransportContext.class.isAssignableFrom(paramType)) {
if (exchange instanceof McpTransportContext transportContext) {
return transportContext;
}
else if (exchange instanceof McpSyncServerExchange syncServerExchange) {
return syncServerExchange.transportContext();
}
else if (exchange instanceof McpAsyncServerExchange asyncServerExchange) {
throw new IllegalArgumentException("Unsupported Async exchange type: "
+ asyncServerExchange.getClass().getName() + " for Sync method: " + method.getName() + " in "
+ method.getDeclaringClass().getName());
}
}
else if (McpSyncServerExchange.class.isAssignableFrom(paramType)) {
if (exchange instanceof McpSyncServerExchange syncServerExchange) {
return syncServerExchange;
}
throw new IllegalArgumentException(
"Unsupported exchange type: " + (exchange != null ? exchange.getClass().getName() : "null")
+ " for Sync method: " + method.getName() + " in " + method.getDeclaringClass().getName());
}
throw new IllegalArgumentException(
"Unsupported exchange type: " + (exchange != null ? exchange.getClass().getName() : "null")
+ " for method: " + method.getName() + " in " + method.getDeclaringClass().getName());
}View on GitHub (pinned to 98a7beda4f)
Solutions
- Register the bean with the sync MCP server so a McpSyncServerExchange is supplied
- Use a separate bean/callback for the async server
- Match transport provider and server types (sync provider with McpServer.sync, async with McpServer.async)
Example fix
// before McpServer.async(provider).prompts(syncCallback).build(); // after McpServer.sync(provider).prompts(syncCallback).build();
Defensive patterns
Strategy: type-guard
Validate before calling
if (exchange instanceof McpAsyncServerExchange) throw new IllegalStateException("Sync callback given async exchange"); Type guard
boolean syncCompatible(Object e) { return e instanceof McpTransportContext || e instanceof McpSyncServerExchange; } Try / catch
try { r = callback.apply(exchange, req); } catch (IllegalArgumentException e) { throw new McpError("Sync/async exchange mismatch"); } Prevention
- Register callbacks only with servers of the matching type
- Separate sync and async beans; do not reuse across servers
- Integration-test each prompt through its real server transport
When it happens
Trigger: A SyncMcpPromptMethodCallback-handled method with an McpTransportContext parameter is invoked while the dispatch path supplies an McpAsyncServerExchange.
Common situations: Registering the same annotated bean with both sync and async servers; wiring an async transport provider to a sync server.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Unsupported Sync exchange type: {syncServerExchange.getClass
- Unsupported Async exchange type: {syncServerExchange.getClas
- Unsupported exchange type: {exchange != null ? exchange.getC
- Sync prompt method must not declare parameter of type: {para
- Unsupported exchange type: {exchange != null ? exchange.getC
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/8e768b49a5f366ee.
Report an issue: GitHub.