{"record":{"id":"deb8f358dad88cba","repo":"alibaba/spring-ai-alibaba","slug":"input-is-not-string","errorCode":null,"errorMessage":"input is not String","messagePattern":"input is not String","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":90,"sourceCode":"\tprivate ListOperatorNode(Mode mode, String inputKey, String outputKey, Predicate<T> filterChain,\n\t\t\tComparator<T> comparatorChain, Long limitNumber, Class<T> type) {\n\t\tthis.mode = mode;\n\t\tthis.inputKey = inputKey;\n\t\tthis.outputKey = outputKey;\n\t\tthis.filterChain = filterChain;\n\t\tthis.comparatorChain = comparatorChain;\n\t\tthis.limitNumber = limitNumber;\n\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};","sourceCodeStart":72,"sourceCodeEnd":108,"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#L72-L108","documentation":"ListOperatorNode.apply reads the value at inputKey from OverAllState. In JSON_STR mode it requires that value to be a Java String containing JSON; if it is any other type (List, Map, number, null) this RuntimeException is thrown. The node deliberately refuses to coerce so malformed workflow state fails fast at the boundary.","triggerScenarios":"Mode is set to Builder Mode.JSON_STR but the state value under inputKey is not a String — e.g. an upstream node already produced a parsed List, or the key is missing (value null).","commonSituations":"Upstream node outputs a real List while ListOperatorNode was configured for JSON string mode; config copied from a JSON-mode example; missing upstream output leaves null in state.","solutions":["Switch the Builder mode to Mode.LIST (or ARRAY) if the upstream value is already a List/array.","Ensure the upstream node serializes its output to a JSON string before this node.","Verify inputKey matches the key the upstream node actually writes.","Wrap apply in error handling that reports the actual type of state.value(inputKey)."],"exampleFix":"// before\nListOperatorNode.<Item>start().mode(Mode.JSON_STR).inputKey(\"items\")... // upstream emits List<Item>\n// after\nListOperatorNode.<Item>start().mode(Mode.LIST).inputKey(\"items\")...","handlingStrategy":"type-guard","validationCode":"Object v = state.value(\"items\").orElse(null);\nif (!(v instanceof String s)) throw new IllegalStateException(\"'items' must be a JSON string, got \" + (v == null ? \"null\" : v.getClass()));","typeGuard":"boolean isJsonStringInput(OverAllState state, String key) {\n    return state.value(key).map(v -> v instanceof String).orElse(false);\n}","tryCatchPattern":"try {\n    out = listOperator.apply(state);\n} catch (RuntimeException e) {\n    if (\"input is not String\".equals(e.getMessage())) {\n        throw new IllegalStateException(\"Configure Mode.LIST or serialize upstream output\", e);\n    }\n    throw e;\n}","preventionTips":["Match the Builder mode to the upstream node's output type.","Keep upstream serialization contracts documented per state key.","Validate state types in a pre-check node in dev/test runs.","Use constants for state keys to avoid silent nulls."],"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"}