spring-projects/spring-ai · error · IllegalArgumentException
List items must be of type String
Error message
List items must be of type String
What it means
SyncStatelessMcpCompleteMethodCallback.convertToCompleteResult throws this IllegalArgumentException when a @McpComplete method returns a List containing non-String elements. MCP completion values must be strings, so the stateless callback cannot build a CompleteCompletion from mixed or typed lists.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/SyncStatelessMcpCompleteMethodCallback.java:111
if (result instanceof CompleteResult) {
return (CompleteResult) result;
}
if (result instanceof CompleteCompletion) {
return new CompleteResult((CompleteCompletion) result);
}
if (result instanceof List) {
List<?> list = (List<?>) result;
List<String> values = new ArrayList<>();
for (Object item : list) {
if (item instanceof String) {
values.add((String) item);
}
else {
throw new IllegalArgumentException("List items must be of type String");
}
}
return new CompleteResult(new CompleteCompletion(values, values.size(), false));
}
if (result instanceof String) {
return new CompleteResult(new CompleteCompletion(List.of((String) result), 1, false));
}
throw new IllegalArgumentException("Unsupported return type: " + result.getClass().getName());
}
/**
* Validates that the method return type is compatible with the complete callback.
* @param method The method to validate
* @throws IllegalArgumentException if the return type is not compatible
*/View on GitHub (pinned to 98a7beda4f)
Solutions
- Return List<String> with only String values
- Map elements to strings: list.stream().map(String::valueOf).collect(toList())
- Remove or skip null and non-String entries before returning
- Declare the method return type as List<String> for compile-time safety
Example fix
// before return ids; // List<Integer> // after return ids.stream().map(String::valueOf).toList();
Defensive patterns
Strategy: validation
Validate before calling
List<?> values = handlerResult();
if (values.stream().anyMatch(v -> !(v instanceof String)))
throw new IllegalStateException("stateless completion values must be Strings"); Type guard
static boolean isAllStrings(List<?> l) { return l.stream().allMatch(String.class::isInstance); } Try / catch
try { return callback.apply(context, request); }
catch (IllegalArgumentException e) { log.warn("non-string completion item: {}", e.getMessage()); return new CompleteResult(new CompleteCompletion(List.of(), 0, false)); } Prevention
- Use List<String> as the declared return type
- Convert enums/IDs with String.valueOf before returning
- Filter nulls: list.stream().filter(Objects::nonNull).map(String::valueOf).toList()
When it happens
Trigger: A stateless @McpComplete handler returns List<Integer>, List<Object>, List<Enum>, or a List with null/mixed elements; triggered from apply() while serving a completion request.
Common situations: Returning enum constants or numeric IDs as suggestions, or streaming rows from a repository into an untyped list.
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
- List items must be of type String
- List items must be of type String
- Parameter must be of type List<McpSchema.Resource>:
- Either prompt or uri must be provided!
- Unsupported return type: {resultType}
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/da82f2fba8e51434.
Report an issue: GitHub.