{"record":{"id":"64092533001f57aa","repo":"alibaba/spring-ai-alibaba","slug":"iteration-end-node-error-wraps-caught-exception","errorCode":null,"errorMessage":"Iteration End node error (wraps caught exception)","messagePattern":"Iteration End node error \\(wraps caught exception\\)","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/IterationNode.java","lineNumber":257,"sourceCode":"\t\t\t\tList<ElementOutput> outputList = new ArrayList<>(\n\t\t\t\t\t\tOBJECT_MAPPER.readValue(state.value(this.outputArrayJsonKey, String.class).orElse(\"[]\"),\n\t\t\t\t\t\t\t\tnew TypeReference<List<ElementOutput>>() {\n\t\t\t\t\t\t\t\t}));\n\t\t\t\t// Check if it's an empty iteration node (i.e. outputStartIterationKey is false)\n\t\t\t\tif (!state.value(this.outputStartIterationKey, Boolean.class).orElse(false)) {\n\t\t\t\t\treturn Map.of(this.outputContinueIterationKey, false, this.outputArrayJsonKey,\n\t\t\t\t\t\t\tOBJECT_MAPPER.writeValueAsString(outputList));\n\t\t\t\t}\n\t\t\t\tList<Integer> indexes = (List<Integer>) state.value(this.taskIndexSetKey, List.class).orElseThrow();\n\t\t\t\tElementOutput result = (ElementOutput) state.value(this.inputResultKey).orElseThrow();\n\t\t\t\t// Add subgraph node processing result to final result array\n\t\t\t\toutputList.add(result);\n\t\t\t\treturn Map.of(this.outputArrayJsonKey, OBJECT_MAPPER.writeValueAsString(outputList),\n\t\t\t\t\t\tthis.outputContinueIterationKey, !indexes.isEmpty());\n\t\t\t}\n\t\t\tcatch (Exception e) {\n\t\t\t\tlog.error(\"Iteration End node error: {}\", e.getMessage(), e);\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic static class Builder<ElementInput, ElementOutput> {\n\n\t\t\tprivate String taskIndexListKey;\n\n\t\t\tprivate String inputResultKey;\n\n\t\t\tprivate String outputArrayKey;\n\n\t\t\tprivate String outputContinueIterationKey;\n\n\t\t\tprivate String outputStartIterationKey;\n\n\t\t\tprivate Builder() {\n\t\t\t\tthis.taskIndexListKey = null;\n\t\t\t\tthis.inputResultKey = null;","sourceCodeStart":239,"sourceCodeEnd":275,"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/IterationNode.java#L239-L275","documentation":"IterationNode's end node (apply) appends the element result to the output list, serializes the accumulated list to JSON, and decides whether iteration should continue. Any exception in that step (JSON serialization failure, missing state keys, index bookkeeping errors) is logged and rethrown as a wrapping RuntimeException. The underlying reason is in the cause.","triggerScenarios":"Running the iteration end node when outputArrayJsonKey state manipulation fails, OBJECT_MAPPER.writeValueAsString throws (unserializable element result), or the task-index list state is corrupted/missing.","commonSituations":"Loop body node returns values that cannot be JSON-serialized into the output array; key mismatch between start/end node builders; nested subgraph mutated the index keys unexpectedly.","solutions":["Inspect e.getCause() for the true error (often JsonProcessingException).","Ensure all loop-body outputs are JSON-serializable objects.","Confirm outputArrayJsonKey, outputContinueIterationKey and index keys are configured identically in start/end builders.","Validate that the subGraph end node writes the expected result key each iteration."],"exampleFix":"// before\ncatch (Exception e) {\n    log.error(\"Iteration End node error: {}\", e.getMessage(), e);\n    throw new RuntimeException(e);\n}\n// after\ncatch (Exception e) {\n    log.error(\"Iteration End node error\", e);\n    throw new RuntimeException(\"Iteration End node failed\", e);\n}","handlingStrategy":"try-catch","validationCode":"Object result = state.value(iteratorResultKey).orElse(null);\nif (result != null) objectMapper.writeValueAsString(result); // fail fast if unserializable","typeGuard":"boolean isSerializableResult(Object o) {\n    try { objectMapper.writeValueAsString(o); return true; } catch (JsonProcessingException e) { return false; }\n}","tryCatchPattern":"try {\n    result = iterationEndNode.apply(state);\n} catch (RuntimeException e) {\n    log.error(\"Iteration end failed, cause: {}\", e.getCause(), e);\n    throw e;\n}","preventionTips":["Ensure loop-body outputs are JSON-serializable POJOs/Maps.","Use identical key constants in start and end builders.","Avoid returning unserializable types (streams, readers) from sub-graph nodes.","Unit test the full loop with representative element types."],"tags":["iteration-node","wrapped-exception","json-serialization"],"backgroundTag":"json-serialization-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}