{"record":{"id":"99b754120c76e9b1","repo":"spring-projects/spring-ai","slug":"list-items-must-be-of-type-string-99b754","errorCode":null,"errorMessage":"List items must be of type String","messagePattern":"List items must be of type String","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/SyncMcpCompleteMethodCallback.java","lineNumber":112,"sourceCode":"\n\t\tif (result instanceof CompleteResult) {\n\t\t\treturn (CompleteResult) result;\n\t\t}\n\n\t\tif (result instanceof CompleteCompletion) {\n\t\t\treturn new CompleteResult((CompleteCompletion) result);\n\t\t}\n\n\t\tif (result instanceof List) {\n\t\t\tList<?> list = (List<?>) result;\n\t\t\tList<String> values = new ArrayList<>();\n\n\t\t\tfor (Object item : list) {\n\t\t\t\tif (item instanceof String) {\n\t\t\t\t\tvalues.add((String) item);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new IllegalArgumentException(\"List items must be of type String\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new CompleteResult(new CompleteCompletion(values, values.size(), false));\n\t\t}\n\n\t\tif (result instanceof String) {\n\t\t\treturn new CompleteResult(new CompleteCompletion(List.of((String) result), 1, false));\n\t\t}\n\n\t\tthrow new IllegalArgumentException(\"Unsupported return type: \" + result.getClass().getName());\n\t}\n\n\t/**\n\t * Validates that the method return type is compatible with the complete callback.\n\t * @param method The method to validate\n\t * @throws IllegalArgumentException if the return type is not compatible\n\t */","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/SyncMcpCompleteMethodCallback.java#L94-L130","documentation":"SyncMcpCompleteMethodCallback.convertToCompleteResult throws this IllegalArgumentException when a @McpComplete method returns a List whose elements are not all String instances. The completion protocol only supports string suggestions, so any non-String element (Integer, POJO, null) makes the result unconvertible.","triggerScenarios":"A @McpComplete handler method returns List<Integer>, List<Object>, a List mixing strings and non-strings, or a List containing null entries; convertToCompleteResult is invoked from apply() while handling a completion request from the MCP client.","commonSituations":"Developers return domain objects or enums as completion values, or collect heterogeneous values from a database into one list, forgetting that MCP completions must be plain strings.","solutions":["Ensure the returned List contains only String elements","Convert non-String values to strings explicitly with String.valueOf(item) or item.toString() before returning","Filter out null or non-String entries before returning the list","Change the method signature to List<String> so the compiler enforces element type"],"exampleFix":"// before\nreturn Arrays.asList(\"a.txt\", 42);\n// after\nreturn Arrays.asList(\"a.txt\", \"42\");","handlingStrategy":"validation","validationCode":"List<?> values = myCompleteMethodResult();\nif (values.stream().anyMatch(v -> !(v instanceof String)))\n    throw new IllegalStateException(\"completion list must contain only Strings\");","typeGuard":"static boolean isStringList(Object o) {\n    return o instanceof List<?> l && l.stream().allMatch(String.class::isInstance);\n}","tryCatchPattern":"try { CompleteResult r = callback.apply(ctx, req); }\ncatch (IllegalArgumentException e) { log.error(\"bad completion payload: {}\", e.getMessage()); return new CompleteResult(new CompleteCompletion(List.of(), 0, false)); }","preventionTips":["Declare handler return types as List<String> so generics enforce element type","Never return raw (unparameterized) List from a completion handler","Unit-test handlers by calling convertToCompleteResult directly"],"tags":["java","mcp","completion","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}