{"record":{"id":"98d78d7b46e40ce0","repo":"invoke-ai/InvokeAI","slug":"iterator-input-type-does-not-match-iterator-output","errorCode":null,"errorMessage":"Iterator input type does not match iterator output type ({edge}): {err}","messagePattern":"Iterator input type does not match iterator output type \\((.+?)\\): (.+?)","errorType":"validation","errorClass":"InvalidEdgeError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/shared/graph.py","lineNumber":1948,"sourceCode":"            raise InvalidEdgeError(f\"Edge creates a cycle in the graph ({edge})\")\n\n    def _validate_edge_field_compatibility(\n        self, edge: Edge, source_node: BaseInvocation, destination_node: BaseInvocation\n    ) -> None:\n        if isinstance(destination_node, CallSavedWorkflowInvocation) and is_call_saved_workflow_dynamic_input(\n            edge.destination.field\n        ):\n            return\n        if not are_connections_compatible(source_node, edge.source.field, destination_node, edge.destination.field):\n            raise InvalidEdgeError(f\"Field types are incompatible ({edge})\")\n\n    def _validate_iterator_edge_rules(\n        self, edge: Edge, source_node: BaseInvocation, destination_node: BaseInvocation\n    ) -> None:\n        if isinstance(destination_node, IterateInvocation) and edge.destination.field == COLLECTION_FIELD:\n            err = self._is_iterator_connection_valid(edge.destination.node_id, new_input=edge.source)\n            if err is not None:\n                raise InvalidEdgeError(f\"Iterator input type does not match iterator output type ({edge}): {err}\")\n\n        if isinstance(source_node, IterateInvocation) and edge.source.field == ITEM_FIELD:\n            err = self._is_iterator_connection_valid(edge.source.node_id, new_output=edge.destination)\n            if err is not None:\n                raise InvalidEdgeError(f\"Iterator output type does not match iterator input type ({edge}): {err}\")\n\n    def _validate_collector_edge_rules(\n        self,\n        edge: Edge,\n        source_node: BaseInvocation,\n        destination_node: BaseInvocation,\n        allow_inputless_source_collector: bool,\n    ) -> None:\n        if isinstance(destination_node, CollectInvocation) and edge.destination.field in (ITEM_FIELD, COLLECTION_FIELD):\n            err = self._is_collector_connection_valid(\n                edge.destination.node_id, new_input=edge.source, new_input_field=edge.destination.field\n            )\n            if err is not None:","sourceCodeStart":1930,"sourceCodeEnd":1966,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/shared/graph.py#L1930-L1966","documentation":"InvalidEdgeError raised by _validate_iterator_edge_rules() when an edge into an IterateInvocation's 'collection' input would break the invariant that the iterator's item output type matches its collection element type. _is_iterator_connection_valid() returns the reason, which is embedded in the message. This runs at add-edge time, before validate_self().","triggerScenarios":"Calling g.add_edge(x, field, iterate_node, \"collection\") where x.field's type conflicts with the type the iterator emits as 'item' (checked via _is_iterator_connection_valid with new_input=edge.source).","commonSituations":"Feeding a non-collection or wrong-element-type output into an iterator, changing the iterator's upstream after downstream consumers were wired for the old item type, hand-edited workflow JSON.","solutions":["Ensure the edge into 'collection' comes from an output whose type is a list of the expected item type","Adjust the iterator's downstream consumers or upstream source so input and item types agree","Wrap single items in a collect/batch node to produce the expected collection type","Update the custom node pack if its output type changed"],"exampleFix":"// before\ng.add_edge(prompt, \"prompt\", iterate, \"collection\")  # str into collection\n// after\ng.add_edge(batch_prompt, \"collection\", iterate, \"collection\")  # list[str]","handlingStrategy":"validation","validationCode":"def iterator_input_ok(graph, iterate_node_id, source) -> bool:\n    return graph._is_iterator_connection_valid(\n        iterate_node_id, new_input=source\n    ) is None\n\nif iterator_input_ok(g, \"iterate_1\", EdgeSource(node_id=\"batch_1\", field=\"collection\")):\n    g.add_edge(\"batch_1\", \"collection\", \"iterate_1\", \"collection\")","typeGuard":"def is_compatible_iterator_input(graph, iterate_node, source) -> bool:\n    if not isinstance(iterate_node, IterateInvocation):\n        return False\n    return graph._is_iterator_connection_valid(\n        iterate_node.id, new_input=source\n    ) is None","tryCatchPattern":"from invokeai.app.services.shared.graph import InvalidEdgeError\n\ntry:\n    g.add_edge(src, src_field, iterate, \"collection\")\nexcept InvalidEdgeError as e:\n    if \"Iterator input type does not match\" in str(e):\n        wrap_source_in_batch_node(src)  # emit a proper collection type\n    else:\n        raise","preventionTips":["Feed iterators only outputs typed as a collection of the intended item type","When changing an iterator's upstream, re-check all item consumers downstream","Validate iterate/collect graphs with validate_self() before saving"],"tags":["invokeai","graph-validation","iterator","type-mismatch"],"backgroundTag":"iterator-type-mismatch","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}