invoke-ai/InvokeAI · error · InvalidEdgeError
Edge creates a cycle in the graph ({edge})
Error message
Edge creates a cycle in the graph ({edge}) What it means
InvalidEdgeError raised by _validate_edge_would_not_create_cycle() when adding a specific edge would introduce a cycle. It builds nx_graph_flat(), temporarily adds the proposed edge, and rejects it if the result is no longer a DAG. This is the add-time counterpart to the whole-graph CyclicalGraphError check.
Source
Thrown at invokeai/app/services/shared/graph.py:1930
def _get_edge_nodes(self, edge: Edge) -> tuple[BaseInvocation, BaseInvocation]:
try:
return self.get_node(edge.source.node_id), self.get_node(edge.destination.node_id)
except NodeNotFoundError:
raise InvalidEdgeError(f"One or both nodes don't exist ({edge})")
def _validate_edge_destination_uniqueness(self, edge: Edge, destination_node: BaseInvocation) -> None:
input_edges = self._get_input_edges(edge.destination.node_id, edge.destination.field)
if len(input_edges) > 0 and (
not isinstance(destination_node, CollectInvocation) or edge.destination.field != ITEM_FIELD
):
raise InvalidEdgeError(f"Edge already exists ({edge})")
def _validate_edge_would_not_create_cycle(self, edge: Edge) -> None:
graph = self.nx_graph_flat()
graph.add_edge(edge.source.node_id, edge.destination.node_id)
if not nx.is_directed_acyclic_graph(graph):
raise InvalidEdgeError(f"Edge creates a cycle in the graph ({edge})")
def _validate_edge_field_compatibility(
self, edge: Edge, source_node: BaseInvocation, destination_node: BaseInvocation
) -> None:
if isinstance(destination_node, CallSavedWorkflowInvocation) and is_call_saved_workflow_dynamic_input(
edge.destination.field
):
return
if not are_connections_compatible(source_node, edge.source.field, destination_node, edge.destination.field):
raise InvalidEdgeError(f"Field types are incompatible ({edge})")
def _validate_iterator_edge_rules(
self, edge: Edge, source_node: BaseInvocation, destination_node: BaseInvocation
) -> None:
if isinstance(destination_node, IterateInvocation) and edge.destination.field == COLLECTION_FIELD:
err = self._is_iterator_connection_valid(edge.destination.node_id, new_input=edge.source)
if err is not None:
raise InvalidEdgeError(f"Iterator input type does not match iterator output type ({edge}): {err}")View on GitHub (pinned to 0b6a024f2f)
Solutions
- Reverse or remove the proposed edge; data must flow one direction
- Insert an IterateInvocation/CollectInvocation to express iteration instead of a feedback edge
- Before adding, check reachability: if dest can reach source, skip the edge
- Restructure the workflow so each node's inputs depend only on earlier nodes
Example fix
// before g.add_edge(denoise, "latents", load_image, "image") # feedback loop // after g.add_edge(load_image, "image", denoise, "image") # forward edge
Defensive patterns
Strategy: validation
Validate before calling
import networkx as nx
def edge_creates_cycle(graph, source_id: str, dest_id: str) -> bool:
return nx.has_path(graph.nx_graph_flat(), dest_id, source_id)
if not edge_creates_cycle(g, src, dst):
g.add_edge(src, "image", dst, "image") Type guard
def is_safe_edge(graph, source_id: str, dest_id: str) -> bool:
g = graph.nx_graph_flat()
return not (g.has_node(source_id) and g.has_node(dest_id)
and nx.has_path(g, dest_id, source_id)) Try / catch
from invokeai.app.services.shared.graph import InvalidEdgeError
try:
g.add_edge(a, "image", b, "image")
except InvalidEdgeError as e:
if "creates a cycle" in str(e):
logger.warning("skipped feedback edge a->b")
else:
raise Prevention
- Before wiring, check whether the destination can already reach the source
- Model iteration with IterateInvocation, not backward edges
- Keep workflow data flow strictly left-to-right/forward in the UI
When it happens
Trigger: Calling g.add_edge(source, ..., dest, ...) where dest already (transitively) feeds source, so the new edge closes a loop.
Common situations: Rewiring feedback loops (e.g. denoise -> preview -> denoise), connecting an output of a downstream node back to an earlier node, scripted wiring computed from user input in the UI.
Related errors
- Graph contains cycles
- Edge source and target types do not match ({edge})
- One or both nodes don't exist ({edge})
- Edge already exists ({edge})
- Field types are incompatible ({edge})
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/b73fbec0a73ccd21.
Report an issue: GitHub.