spring-projects/spring-ai · error · java.lang.IllegalArgumentException

Method cannot have more than one Map parameter: {method.getN

Error message

Method cannot have more than one Map parameter: {method.getName()} in {method.getDeclaringClass().getName()}

What it means

A prompt method may declare at most one Map parameter (used to receive all prompt arguments). AbstractMcpPromptMethodCallback.validateParameters throws this IllegalArgumentException when a second Map-assignable parameter is found during callback registration. The framework cannot know which map should receive the arguments map.

Source

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

				hasRequestContextParam = true;
			}
			else if (isSupportedExchangeOrContextType(paramType)) {
				if (hasExchangeParam) {
					throw new IllegalArgumentException("Method cannot have more than one exchange parameter: "
							+ method.getName() + " in " + method.getDeclaringClass().getName());
				}
				hasExchangeParam = true;
			}
			else if (GetPromptRequest.class.isAssignableFrom(paramType)) {
				if (hasRequestParam) {
					throw new IllegalArgumentException("Method cannot have more than one GetPromptRequest parameter: "
							+ method.getName() + " in " + method.getDeclaringClass().getName());
				}
				hasRequestParam = true;
			}
			else if (Map.class.isAssignableFrom(paramType)) {
				if (hasMapParam) {
					throw new IllegalArgumentException("Method cannot have more than one Map parameter: "
							+ method.getName() + " in " + method.getDeclaringClass().getName());
				}
				hasMapParam = true;
			}
			// Other parameter types are assumed to be individual arguments
		}
	}

	protected abstract Object assignExchangeType(Class<?> paramType, Object exchange);

	/**
	 * Builds the arguments array for invoking the method.
	 * <p>
	 * This method constructs an array of arguments based on the method's parameter types
	 * and the available values (exchange, request, arguments).
	 * @param method The method to build arguments for
	 * @param exchange The server exchange
	 * @param request The prompt request

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Keep only one Map parameter; consolidate options into the single arguments Map.
  2. Replace the extra Map with individually annotated @McpArg parameters so the framework binds them by name from request.arguments().
  3. Wrap secondary map data in a custom POJO and bind it from a single @McpArg value if the framework supports it.

Example fix

// before
@McpPrompt(name = "search")
public List<String> search(Map<String, Object> args, Map<String, String> filters) { ... }
// after
@McpPrompt(name = "search")
public List<String> search(Map<String, Object> args) { ... }
Defensive patterns

Strategy: validation

Validate before calling

long mapParams = Arrays.stream(method.getParameters())
    .map(Parameter::getType)
    .filter(Map.class::isAssignableFrom)
    .count();
if (mapParams > 1) throw new IllegalStateException(method + " declares multiple Map parameters");

Prevention

When it happens

Trigger: Registering a method like `myPrompt(Map<String,Object> args, Map<String,String> options)` — any two parameters assignable to java.util.Map trigger it, since the check is `Map.class.isAssignableFrom(paramType)` with hasMapParam already true.

Common situations: Adding an options/metadata Map to an existing arguments Map; generic utility methods that take multiple Map parameters being adapted into prompt handlers; type erasure makes both Map<K,V> variants look identical to the check.

Understand the failure class

Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.

Related errors


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