{"record":{"id":"fed2c88b8cb99854","repo":"alibaba/spring-ai-alibaba","slug":"input-is-not-list","errorCode":null,"errorMessage":"input is not List","messagePattern":"input is not List","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-boot-starters/spring-ai-alibaba-starter-builtin-nodes/src/main/java/com/alibaba/cloud/ai/graph/node/ListOperatorNode.java","lineNumber":98,"sourceCode":"\t\tthis.type = type;\n\t}\n\n\t@Override\n\tpublic Map<String, Object> apply(OverAllState t) throws Exception {\n\t\ttry {\n\t\t\tObject inputObject = t.value(inputKey).orElse(null);\n\t\t\tList<T> inputList = switch (mode) {\n\t\t\t\tcase JSON_STR -> {\n\t\t\t\t\tif (!(inputObject instanceof String)) {\n\t\t\t\t\t\tthrow new RuntimeException(\"input is not String\");\n\t\t\t\t\t}\n\t\t\t\t\tString inputJsonString = inputObject.toString();\n\t\t\t\t\tJavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, type);\n\t\t\t\t\tyield objectMapper.readValue(inputJsonString, javaType);\n\t\t\t\t}\n\t\t\t\tcase LIST -> {\n\t\t\t\t\tif (!(inputObject instanceof List)) {\n\t\t\t\t\t\tthrow new RuntimeException(\"input is not List\");\n\t\t\t\t\t}\n\t\t\t\t\tyield (List<T>) inputObject;\n\t\t\t\t}\n\t\t\t\tcase ARRAY -> {\n\t\t\t\t\tif (inputObject == null || !inputObject.getClass().isArray()) {\n\t\t\t\t\t\tthrow new RuntimeException(\"input is not Array\");\n\t\t\t\t\t}\n\t\t\t\t\tyield Arrays.asList((T[]) inputObject);\n\t\t\t\t}\n\t\t\t};\n\t\t\tList<T> listElements = inputList.stream()\n\t\t\t\t.filter(filterChain)\n\t\t\t\t.sorted(comparatorChain)\n\t\t\t\t.limit(limitNumber != null && limitNumber > 0 ? limitNumber : Long.MAX_VALUE)\n\t\t\t\t.toList();\n\n\t\t\tObject output = switch (mode) {\n\t\t\t\tcase JSON_STR -> objectMapper.writeValueAsString(listElements);","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-boot-starters/spring-ai-alibaba-starter-builtin-nodes/src/main/java/com/alibaba/cloud/ai/graph/node/ListOperatorNode.java#L80-L116","documentation":"In LIST mode, ListOperatorNode.apply requires the state value at inputKey to be an instance of java.util.List. If it is anything else (a JSON string, array, null) this RuntimeException is thrown. It's a runtime type guard so the subsequent (List<T>) cast is safe.","triggerScenarios":"Mode LIST configured while upstream node wrote a JSON string, a primitive array, a Map, or nothing (null) under inputKey.","commonSituations":"Mixing nodes that emit JSON strings with nodes expecting structured lists; refactoring upstream output from List to serialized JSON; key collisions in OverAllState overwriting the list.","solutions":["Set mode to JSON_STR if the upstream value is a JSON string.","Ensure the upstream node writes an actual List under inputKey.","Check for state-key collisions where another node overwrites the value.","Add a pre-check node validating the state value type before ListOperatorNode runs."],"exampleFix":"// before\nListOperatorNode.<Item>start().mode(Mode.LIST).inputKey(\"items\")... // items is a JSON string\n// after\nListOperatorNode.<Item>start().mode(Mode.JSON_STR).inputKey(\"items\")...","handlingStrategy":"type-guard","validationCode":"Object v = state.value(\"items\").orElse(null);\nif (!(v instanceof List)) throw new IllegalStateException(\"'items' must be a List for Mode.LIST, got \" + (v == null ? \"null\" : v.getClass()));","typeGuard":"boolean isListInput(OverAllState state, String key) {\n    return state.value(key).map(v -> v instanceof List<?>).orElse(false);\n}","tryCatchPattern":"try {\n    out = listOperator.apply(state);\n} catch (RuntimeException e) {\n    if (\"input is not List\".equals(e.getMessage())) {\n        throw new IllegalStateException(\"Upstream emitted non-List for key; switch mode or fix upstream\", e);\n    }\n    throw e;\n}","preventionTips":["Only use Mode.LIST when the producer writes a real java.util.List.","Remember Jackson JSON parsing yields Lists, not Strings — prefer LIST mode after parsing.","Guard against state-key overwrites between nodes.","Add integration tests across node boundaries."],"tags":["list-operator","type-mismatch","state-graph"],"backgroundTag":"type-mismatch","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}